CodeZine(コードジン)

特集ページ一覧

PHPでのストリーム処理の実装

PHPエクステンションの作り方 第6回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2014/01/21 14:00
目次

URL記述からのPHPストリームの作成

 続いて、URL風の記述を用いてのストリーム作成の方法を紹介します。おおよその流れはメソッドからのストリームの作成と同様ですが、これまではストリームをオープンするところからでした。しかし、URL記述からですので多少異なり、以下のような流れになります。

  1. ストリームの状態を管理する構造体を用意する
    (メソッドから取得するストリームで用意したものを再利用可能)。
  2. ストリームの読み込み(read)、書き込み(write)、クローズ(close)などを行うための関数を用意する
    (メソッドから取得するストリームで作成したものを再利用可能)。
  3. 2で作成した関数をハンドラとして登録する構造体を用意する
    (メソッドからの取得するストリームで作成したものを再利用可能)。
  4. 3で作成した構造体を用いてファイルをオープンする関数を作成する。
  5. 4で作成した関数をハンドラとして登録する構造体を用意する。
  6. モジュールとして新たなストリームプロトコルとして利用できるように、5で作成した構造体をモジュールの初期化処理で登録する。

 1から3までは今まで作成したものをほぼそのまま再利用可能で、その流れも変わりません。4はメソッドからの取得の場合には、PZipFile::getStream()として実装していた部分ですが、今回はURLスキームをパースして実際のリソースをオープンする処理を新たに記述する必要があります。5、6はPHP全体に対してそのURLスキームを用いたときに、指定した関数が動作するようにするための処理になります。

ストリームをオープンする

 4でのストリームをオープンする処理の実装を行っていきます。実際のコードを記述するには、ほぼ同様の処理を行っているPHPソース内のext/zip/zip_stream.cのphp_stream_zip_opener関数を参考にし、新たに関数を以下のように作成します。ただし、今回は暗号付きZipファイルの解凍を行いますので、パスワードを設定する必要があります。そのパスワードを設定する方法には2つの方法があります。

  • URL文字列にパスワードを設定する方法
  • コンテキストを通じてパスワードを設定する方法
URL記述からストリームをオープンする関数の実装(pzip_stream.cからの抜粋)
php_stream *php_stream_pzip_opener(php_stream_wrapper *wrapper,
    char *path,  // ……(1)
    char *mode,
    int options,
    char **opened_path,
    php_stream_context *context STREAMS_DC TSRMLS_DC)  // ……(2)
{
  : // (省略)
}

 (1)のpath変数は、URLの文字列が設定される引数で、(2)context変数はストリームのコンテキストが設定される引数です。

URL文字列をパースする

 PHPから以下のような文字列としてURLが設定される場合を想定します。

URLのクエリー文字列としてパスワードを設定する
$fp = fopen("pzip:///home/guest/file.zip?password=abcedefg#file1.txt","r");

 URL文字列をパースしてパスワードを設定する方法の場合、あまりPHPモジュール固有の知識は必要なく実装できますが、ここでは、PHPのモジュール開発時に利用できる関数を使用してパースを行います。

URLをパースする処理(pzip_stream.cの抜粋)
php_url *url = NULL;                                // ……(1)
char *tmppath;
if(strncasecmp("pzip:///",path,8) == 0){  // ……(2)
    int count , new_len = 0;
    tmppath = php_str_to_str_ex(   // ……(3)
        path,strlen(path),"pzip:///", strlen("pzip:///"),
        "pzip://localhost/",strlen("pzip://localhost/"),
        &new_len,0,&count);
    url = php_url_parse(tmppath);  // ……(4)
    efree(tmppath);
}
: // (省略)
if(url->query){  // ……(5)
    char *saveptr;
    char *token;
    token = php_strtok_r(url->query,"?",&saveptr);  // ……(6)
    while(1){
        if(token == NULL){
            break;
        }
        else{
            if(strncasecmp("password=",token,9) == 0){     // ……(7)
                token += 9;
                password = estrdup(token);                           // ……(8)
            }
            token = php_strtok_r(NULL,"?",&saveptr);
        }
    }
}
: // (省略)

 (1)php_urlの構造体を用意します。この構造体はPHPの関数であるparse_url()関数を実行した時の結果とほぼ同様の構造です。(2)でURLの文字列が"pzip:///"で開始されているかをチェックします。残念ながら(4)で行うphp_url_parse()関数はscheme://hostのように必ずhostがあることを想定しており、処理が失敗してしまいます。そこで、(3)php_str_to_str_ex()では、"pzip:///"という文字列を"pzip://localhost/"という文字列に置換します。このように少々分かりにくい関数名ではありますが、PHPでのstr_replace相当の関数も用意されています。これらの関数はマニュアルがそろっている訳ではないので、根気よくほかのモジュールで使われている関数を探す必要があります。

 これでURLとしてパースできる文字列が完成しましたので、(4)php_url_parse()で文字列をパースしてphp_url構造体として結果を取得します。クエリー文字列は(5)url->queryとして取得できますので、それを(6)php_strtok_r()を用いて"?"で区切られるトークンとして処理をしていきます。(7)では文字列が"password="で始まっている場合には、(8)そのトークンをパスワードとして設定します。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:PHPエクステンションの作り方

著者プロフィール

  • WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。個人紹介主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしど...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5