ウエブAPIを用いた初めてのCGI (PHP編) プログラム演習4
今回はPHP言語で前回と同様の仕様でサイトを開発してみましょう。主に処理は前回同様
に分かれます。
本題に入る前に少し脱線して、PHPでライブラリを使うための準備の解説をします。PHP5では標準でさまざまなライブラリが組み込まれた形で提供されている場合が多いです(環境によってことなるので一律ではない。自前でコンパイルしてPHPを作った場合はその時点で任意に決定できる)。自分のPHP環境でどのようなライブラリが利用できるかを調べる場合は
bash-3.2$ cat phpinfo.php <?php phpinfo(); ?>
というファイルを作成し、これにアクセスしてみてください。
PHPの環境変数。組み込み済みモジュール一覧などさまざまな情報が確認できます。
↑例えばSimpleXMLライブラリがインストール済みであることが分かる
よく使うライブラリはmbstring, simpleXML, curl, mysqli などがあります。
また、後から拡張可能なモジュールとして pear, peclなどが利用できます. pearで利用したいパッケージがある場合は, pearコマンドを利用してインストールします。
(MAMP環境でのpearインストールの例) bash-3.2$ sudo /Applications/MAMP/bin/php5/bin/pear install HTTP_Client Password: WARNING: channel "pear.php.net" has updated its protocols, use "channel-update pear.php.net" to update WARNING: "pear/Net_URL" is deprecated in favor of "pear/Net_URL2" downloading HTTP_Client-1.2.1.tgz ... Starting to download HTTP_Client-1.2.1.tgz (10,202 bytes) .....done: 10,202 bytes downloading HTTP_Request-1.4.3.tgz ... Starting to download HTTP_Request-1.4.3.tgz (16,791 bytes) ...done: 16,791 bytes downloading Net_URL-1.0.15.tgz ... Starting to download Net_URL-1.0.15.tgz (6,303 bytes) ...done: 6,303 bytes downloading Net_Socket-1.0.9.tgz ... Starting to download Net_Socket-1.0.9.tgz (5,173 bytes) ...done: 5,173 bytes install ok: channel://pear.php.net/Net_URL-1.0.15 install ok: channel://pear.php.net/Net_Socket-1.0.9 install ok: channel://pear.php.net/HTTP_Request-1.4.3 install ok: channel://pear.php.net/HTTP_Client-1.2.1
XML_Serializerも使うのであわせてインストールしてください。ただし、XML_Serializerは現在betaパッケージなのでこの場合は
bash-3.2$ sudo /Applications/MAMP/bin/php5/bin/pear install XML_Serializer-beta
と -betaを最後につけます。最終的にインストール一覧を確認したい場合は pear listコマンドで
bash-3.2$ /Applications/MAMP/bin/php5/bin/pear list Installed packages, channel pear.php.net: ========================================= Package Version State Archive_Tar 1.3.2 stable Console_Getopt 1.2.3 stable HTTP_Client 1.2.1 stable HTTP_Request 1.4.3 stable Net_Socket 1.0.9 stable Net_URL 1.0.15 stable PEAR 1.6.1 stable Structures_Graph 1.0.2 stable XML_Parser 1.3.1 stable XML_Serializer 0.19.1 beta XML_Util 1.2.0 stable
確認できます。実際のインストール場所は phpinfo()で確認できる include_path のフォルダ以下にインストールされ require_onceでPHPプログラムから呼び出されます。
bash-3.2$ cat index.php <?php require_once('HTTP/Client.php'); require_once('XML/Unserializer.php'); $SEARCH_API_HOST = 'search.yahooapis.jp'; $SEARCH_API_URL = '/WebSearchService/V1/webSearch'; $SEARCH_API_APPID = 'p3O1lFOxg66up7VWRDmVkEJnF6baGNJj38rT6gUY3DzyF.kX4_PepRsfnk1AYss1J.YG'; error_log('script start'); print<<<EOM <html> <head> <title>Sample Program 4 php-1</title> <meta http-equiv="Content-Type" content="text/html" charset="utf-8"> </head> <body> EOM; print '<form action="./'. basename($_SERVER['SCRIPT_NAME']) .'">'; print '<input type="text" name="query" value="' . $_GET['query'] . '">'; print '<input type="submit" value="search">'; print '</form>'; $responseXML = ''; # HTTPでXMLを取得する (socket関数を利用) if(0) { $socket = fsockopen($SEARCH_API_HOST, 80, $errno, $errstr, 30); $request = "GET ${SEARCH_API_URL}?appid=${SEARCH_API_APPID}&query=".urlencode($_GET['query']) . " HTTP/1.0\r\n\r\n"; fwrite($socket, $request); $response = ''; while($out = fgets($socket, 1024)) { $response .= $out; } fclose($socket); $tmp = explode("\r\n\r\n", $response, 2); $responseXML = $tmp[1]; } # HTTPでXMLを取得する (HTTP_Clientライブラリを利用) if(0) { $client = new HTTP_Client(); $status = $client->get("http://${SEARCH_API_HOST}${SEARCH_API_URL}?appid=${SEARCH_API_APPID}&query=".urlencode($_GET['query'])); $response = $client->currentResponse(); $responseXML = $response['body']; } # HTTPでXMLを取得する (curlライブラリを利用) if(1) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "http://${SEARCH_API_HOST}${SEARCH_API_URL}?appid=${SEARCH_API_APPID}&query=".urlencode($_GET['query'])); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $responseXML = curl_exec($curl); curl_close($curl); } # HTTPでXMLを取得する (file_get_contents関数を利用) if(0) { $responseXML = file_get_contents("http://${SEARCH_API_HOST}${SEARCH_API_URL}?appid=${SEARCH_API_APPID}&query=".urlencode($_GET['query'])); print_r($response); } # XMLの解析と出力 ( XML_Unserializerを利用 ) if(0) { $unserializer = new XML_Unserializer(array( XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => 'parseAttributes' )); $unserializer->unserialize($responseXML); $hashData = $unserializer->getUnserializedData(); foreach($hashData['Result'] as $site) { print("<li><a href=\"{$site['ClickUrl']}\">{$site['Title']}</a>\n"); } } # XMLの解析と出力 ( simpleXML を利用 ) if(1) { $xmlObj = simplexml_load_string($responseXML); // simplexml_load_file で一気に取得も可能 foreach($xmlObj->{'Result'} as $site) { print("<li><a href=\"{$site->{'ClickUrl'}}\">{$site->{'Title'}}</a>\n"); } } print<<<EOM </body> </html> EOM; error_log('query=' . $_GET['query']); error_log('script end'); exit; ?>
さまざまな方法で実現可能なことが分かると思います。 file_get_contents および simplexml_load_fileは簡単に利用でき便利ですが、この方法は一部の環境でセキュリティの観点から利用できません(php.ini で allow_url_fopen=Offと設定されている)。私の主観ですが curl + simpleXMLを利用するのがオススメです。 XML_UnserializerでXMLをハッシュ型変数にする方が後の処理が簡易になるのでこちらも一般的ですが、pearでのインストールが必要な点とパフォーマンスの点でsimpleXMLの方が有利です。用途に応じて使い分けるのが良いと思います。
【演習】
上のプログラムは随所でエラー処理を省略しています。たとえば
- キーワードが入力されていない状態でのアクセス時にもHTTP接続してしまう
- ウエブサーバにアクセスできない場合のエラー処理
- 応答したXMLが不完全で、解析処理が失敗した場合
- 検索結果が0件の場合、(検索結果が1件の場合もこのままでは不完全な場所があります)
これらのケースに適切な処理に変更して完全なものにしてみましょう。
【演習】
10件目以降も表示できるように拡張しましょう。その際にpearにPagerというライブラリがあります。これを用いると、簡単に検索結果下部にある、ページ切り替えのモジュールを実現することが可能です。pear利用ドキュメントもしくは利用を解説しているウエブページなどを調べて実現させてみましょう。