第4回 HTTP_Download クラス - ダウンロード支援ライブラリ - PEAR講座

PHPセキュリティ

くまっち先生のPEAR講座

Lecutures on PHP

第4回 HTTP_Download クラス - ダウンロード支援ライブラリ (その1)

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

HTTP_Downloadとは?

HTTP_Downloadは、データダウンロードに関する処理を簡単に実現することのできるパッケージです。データを「ダウンロードする」ためのライブラリではなく「ダウンロードさせる」ためのライブラリで、例えば指定したファイルをダウンロードさせるためには、リスト1のようなプログラムコードで実現できます。

 リスト1HTTP_Download 使用例1

 
require_once 'HTTP/Download.php';

 
$httpDownload = new HTTP_Download();
 
$httpDownload->setFile('example.txt');
 
$httpDownload->send();

またリスト2のように、テキストデータ(文字列)をファイルとしてダウンロードさせることもできます。

 リスト2HTTP_Download 使用例2

 
require_once 'HTTP/Download.php';
 
$httpDownload = new HTTP_Download();
 
$httpDownload->setData('テキストデータの例です。');
 
$httpDownload->setContentDisposition(HTTP_DOWNLOAD_ATTACHMENT,
                                      
'example.txt'
                                      
);
 
$httpDownload->send();

くまっち先生上記2例ともに、ブラウザでアクセスすると「example.txt」というファイルを保存するためのウィンドウがポップアップし、実際にダウンロードを実施することができます。使用例1の場合はexample.txtのテキストデータそのものが、使用例2の場合は「テキストデータの例です。」と書かれたテキストデータがファイルとしてダウンロードされることになります。

このようにHTTP_Downloadを利用することで簡単にデータダウンロード処理が実現できます。実際のファイルだけでなく任意のデータも指定できますので非常に実用性の高いライブラリの1つです。

コンストラクタによるセットアップ

それでは順に内部コードを見ていくことにしましょう。まずはクラスコンストラクタです。PHP4の頃から提供されているライブラリのため、リスト3のようにPHP4向けコンストラクタの記述方法 (*1) になっています。

 リスト3HTTP_Downloadコンストラクタ

 
function HTTP_Download($params array())
 {
   
$this->HTTP = &new HTTP_Header;
   
$this->setParams($params);
 }

くまっち先生ここではクラスを動作させるための初期設定として、前回紹介したHTTP_Headerクラスを生成させHTTP_Downloadクラスのプロパティに格納しています。後に紹介しますが、ダウンロード処理を行う際に何らかのHTTPヘッダ情報を取り扱う場合に利用することになります。コンストラクタはクラスを生成する際必ず実行される処理内容になりますので、このようにセットアップ処理を実施するには最適のフェーズです。

ちなみに生成したHTTP_Headerクラスは、プロパティへリファレンスで代入 (先頭にアンパサンドを付与している) されています。

PHP5ではnewによるクラス(オブジェクト)の生成結果は自動的にリファレンスになりますが、PHP4ではオブジェクトのコピーになります。オブジェクト内における値の操作を行うと結果としてコピーとして生成されたオブジェクトとは内容の不一致が起きる可能性があり、また動作パフォーマンスやメモリ使用量の点でも注意が促されています。したがってPHP4上においてもオブジェクトはリファレンスで利用するほうがトラブルもなく良いため、本処理でもクラスをリファレンスで代入しています。

続いて登場するsetParamsメソッドは、前述した使用例でも登場した「setXXX」というメソッドを連続実行するための機能です。リスト4がそのコード内容です。

 リスト4setParamsメソッド

 
function setParams($params)
 {
   foreach((array
$params as $param => $value){
     
$method 'set'$param;
            
     if (!
method_exists($this$method)) {
       return 
PEAR::raiseError(
           
"Method '$method' doesn't exist.",
            
HTTP_DOWNLOAD_E_INVALID_PARAM
          
);
     }
            
     
$e call_user_func_array(array(&$this$method), (array$value);
            
     if (
PEAR::isError($e)) {
       return 
$e;
     }
   }
     return 
true;
 }

「setXXX」メソッド群はHTTP_Downloadが動作するために必要なパラメータを設定するための機能として準備されています。(*2)くまっち先生

連想配列として与えられた引数をforeach構文で展開し、連想配列のキー(インデックス)の値を利用して「setXXX」(XXX部分がインデックスの値)という名称を生成します。そしてcall_user_func_array関数を使用して、作成したsetXXXを本クラス内にあるメソッドとして実行します。このとき生成した名称に相当するメソッドがクラス内に存在するかどうか、およびメソッドを正しく実行できたかどうかの確認をそれぞれで行い、適切にエラー(PEARによるエラーオブジェクト)を返すようにしています。

ここでメソッド実行にcall_user_func_array関数を利用しているのは、実行しようとするメソッドの引数の数が一定ではないからです。リスト5のようにメソッドの引数の数が異なる場合も、この関数を利用することで任意数の引数を1つの配列として扱うことができます。今回のように処理の流れを一括してまとめたいケースにも柔軟に対応できるため、覚えておきたいテクニックの1つです。

 リスト5call_user_func_array利用例

 
// 任意のメソッドに対して引数の数が異なるケースが…
 
$this->serFoo('foo');
 
$this->serFooBar('foo''bar');
 
$this->serFooBarBaz('foo''bar''Baz');

 
// call_user_func_arrayならば許容可能
 
$jobs array('setFoo'       => array('foo'),
               
'setFooBar'    => array('foo''bar'),
               
'setFooBarBaz' => array('foo''bar''baz')
               );
 foreach (
$jobs as $method => $params) {
   
call_user_func_array(array(&$this$method), $params);
 }

 
// これでも動作するが、eval関数は動作パフォーマンスに難あり
 
$jobs array('setFoo'       => 'foo',
               
'setFooBar'    => 'foo, bar',
               
'setFooBarBaz' => 'foo, bar, baz'
               
);
 foreach (
$jobs as $method => $params) {
   eval(
'$this->$method(' $params ');');
 }
----

*1)
http://jp.php.net/manual/ja/language.oop.constructor.php

*2)
http://pear.php.net/manual/ja/package.http.http-download.setparams.php

  • 1
  • 2

  



Pick Up Q&A

Q
負荷時のmysql_connect()エラー
 このエントリーをはてなブックマークに追加 
A
これはPHPというよりOSまたはMySQLのコミュニティで質問されたほうがいいと思います。 ぱっと思いついた範囲で記すと MySQL等のDBに「ある時点において同時に接続可能なクライアントの最大数」に制限があるよう...

>>続きを読む

今回のような実践的な経験がエンジニアのキャリアに繋がると思います。是非サービスを成功させて下さい!

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)