SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

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

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

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

  • X ポスト
  • このエントリーをはてなブックマークに追加

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)そのトークンをパスワードとして設定します。

次のページ
最後に

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
PHPエクステンションの作り方連載記事一覧

もっと読む

この記事の著者

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

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

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

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7576 2014/01/21 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング