curlというコマンドを使えば、Linuxなどのサーバー上でコマンドラインから簡単にHTTPやFTPなどのリクエストを処理することができます。
PHPのcURL関数 は、そのcurlコマンドと同等の機能を関数レベルで提供してくれます。
このcURL関数を使って、HTTPクライアントをプログラム上に実装してみたいと思います。
ちなみに、プログラムをHTTPクライアントとして動作させたい場合は、PEARのHTTP_Client を利用した方が直感的でわかりやすいかもしれません。
PEARのHTTP_Clientの利用法は、「Twitterのタイムラインを取得するPHPスクリプト 」で簡単に触れていますので、そちらも合わせてどうぞ。
あるサイトへアクセスしてHTMLを取得する
まずは、PHPのプログラムからとあるサイトへアクセスし、ブラウザ同様にHTMLを取得すると言うことをやってみます。
<?php $url = 'http://www.example.com/'; $ch = curl_init($url); // HTTPヘッダを出力しない curl_setopt($ch, CURLOPT_HEADER, FALSE); // 返り値を文字列として受け取る curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // HTTPステータスコード400の以上の場合も何も処理しない curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); // サイトへアクセス $result = curl_exec($ch); // HTTPステータスコードをチェックしエラーならエラー内容を出力 if(curl_errno($ch)) { echo 'Curl error: ' . curl_error($ch); } // セッションをクローズ curl_close($ch); // リクエストの内容を出力 var_dump($result);
これで、URIが正しければきちんとそのHTMLソースを受信することができます。
cURL関数は、curl_setopt関数 で細かなリクエストの処理を変えることが出来ます。
例えば、上記の場合はHTMLのみを受信しますが、HTTPヘッダも合わせて取得したければ、
// HTTPヘッダも出力 curl_setopt($ch, CURLOPT_HEADER, TRUE);
とすることで、下記のようにHTTPヘッダを受け取ることも出来ます。
string(282) "HTTP/1.1 200 OK Date: Thu, 22 Apr 2010 15:12:41 GMT Server: Apache/2.2.3 (CentOS) Last-Modified: Thu, 22 Apr 2010 14:39:46 GMT ETag: "1e7c03a-22-4831d080" Accept-Ranges: bytes Content-Length: 34 Connection: close Content-Type: text/html
また、「CURLOPT_FAILONERROR」オプションをTRUEに設定しておかないと、400以上のHTTPステータスコードが返ってきた場合でも、そのままエラーページのHTMLを表示します。
例えば、存在しないファイルへアクセスした場合、HTTPステータスコード404を返しますが、その404のエラーページのHTMLを受け取ってしまいます。
データをPOSTしてそのリクエストを受け取る
次は、とあるページにデータをPOSTし、そのリクエストを取得してみます。
POSTする先のプログラムは、下記のようにしておきます。
<?php if ($_POST['var'] !== "") { echo "hello"; }
上記のプログラムへデータをPOSTするプログラムを書きます。
<?php $url = 'http://www.examle.com/post.php'; // POSTするデータを連想配列で格納 $post_data['var'] = "hoge"; $ch = curl_init($url); // HTTPヘッダを出力しない curl_setopt($ch, CURLOPT_HEADER, FALSE); // 返り値を文字列として受け取る curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // HTTPステータスコード400の以上の場合も何も処理しない curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); // POSTするデータをセット curl_setopt($ch,CURLOPT_POSTFIELDS, $post_data); // サイトへアクセス $result = curl_exec($ch); // HTTPステータスコードをチェックしエラーならエラー内容を出力 if(curl_errno($ch)) { echo 'Curl error: ' . curl_error($ch); } // セッションをクローズ curl_close($ch); // リクエストの内容を出力 var_dump($result);
結果は、下記のようにプログラムからの出力結果を受け取ることができます。
string(5) "hello"
POSTするデータは、連想配列にセットしておき「CURLOPT_POSTFIELDS」オプションでまとめて渡します。
Basic認証をクリアしてその先のページへアクセスする
次は、SSL環境下でBasic認証がかかっているHTMLファイルへアクセスしてみます。
SSLアクセスと、Basic認証を実行する場合のオプションがそれぞれ加わります。
<?php $url = 'https://www.example.com'; $basic_user = "foo"; $basic_password = "password"; $ch = curl_init($url); // HTTPヘッダを出力しない curl_setopt($ch, CURLOPT_HEADER, FALSE); // SSLバージョン3を利用する curl_setopt($ch, CURLOPT_SSLVERSION, 3); // 返り値を文字列として受け取る curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // サーバー証明書の検証をスキップ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // HTTPステータスコード400の以上の場合も何も処理しない curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); // Basic認証のユーザー名:パスワードをセット curl_setopt($ch, CURLOPT_USERPWD, $basic_user . ":" . $basic_password); // サイトへアクセス $result = curl_exec($ch); // HTTPステータスコードをチェックしエラーならエラー内容を出力 if(curl_errno($ch)) { echo 'Curl error: ' . curl_error($ch); } // セッションをクローズ curl_close($ch); // リクエストの内容を出力 var_dump($result);
Basic認証をクリアするために「CURLOPT_USERPWD」オプションと、SSL証明書の検証をスキップするための「CURLOPT_SSL_VERIFYPEER」「CURLOPT_SSL_VERIFYHOST」オプションをFALSEにセットしています。
curlは、対象ホストの情報とSSL証明書の情報が一致するか厳密にチェックするため、そのようなシステム構成になっていない場合は、処理をスキップさせるようにする必要があります。
おまけ: cURL関数を使ってTwitterへデータをPOSTする
「Twitterへ投稿するPHPスクリプト 」では、PEARのHTTP_Clientを利用してプログラムを書いてみましたが、今回のcurlでの処理を応用して書き直して見ます。
<?php $url = 'https://twitter.com/statuses/update.xml'; $twitter_user = "your_twitter_id"; $twitter_password = "your_twitter_password"; // TwitterへPOSTする内容 $tweet['status'] = "hello"; $ch = curl_init($url); // HTTPヘッダを出力しない curl_setopt($ch, CURLOPT_HEADER, FALSE); // SSLバージョン3を利用する curl_setopt($ch, CURLOPT_SSLVERSION, 3); // 返り値を文字列として受け取る curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // サーバー証明書の検証をスキップ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // HTTPステータスコード400の以上の場合も何も処理しない curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); // TwitterAPIのBasic認証のユーザー名:パスワードをセット curl_setopt($ch, CURLOPT_USERPWD, $twitter_user . ":" . $twitter_password); // ツイートするデータをセット curl_setopt($ch, CURLOPT_POSTFIELDS, $tweet); // Expectヘッダを抑制 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); // サイトへアクセス $result = curl_exec($ch); // HTTPステータスコードをチェックしエラーならエラー内容を出力 if(curl_errno($ch)) { echo 'Curl error: ' . curl_error($ch); } // セッションをクローズ curl_close($ch); // リクエストの内容を出力(XMLで返ってくるので実際は解析処理が必要) var_dump($result);
今回はHTTPSで通信するバージョンで書いてみました。
また、今までのプログラムと比べ、「CURLOPT_HTTPHEADER」というオプションを加えています。
これを加えなかった場合、TwitterのAPIより下記のようなメッセージが返ってきます。
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>417 Expectation Failed</title> </head><body> <h1>Expectation Failed</h1> <p>The expectation given in the Expect request-header field could not be met by this server.</p> <p>The client sent<pre> Expect: 100-continue </pre> but we only allow the 100-continue expectation.</p> </body></html>
クライアント側から「Expect: 100-continue」リクエストを投げろと要求してるけど、Twitterのサーバーでは許可してないよって返ってくるので、「Expect:」ヘッダを加えています。
で、この「100-continue」リクエストというのは、大きなデータを投げるときに、まずはヘッダ情報だけを投げ、「100 Continue」のレスポンスが返ってきたらボディ(データ本体)を投げるというHTTP1.1の仕様のようです。
参考: Twitter APIの417 Expectation Failed対策 @ エスカフラーチェブログ
やっぱり、HTTP_Clientを使うより若干手間がかかりますね。。。
[PR]格安固定IPが【5分で発行】+【初期無料】+【2ヶ月無料体験】
[PR]初心者おススメ!24時間サポートセキュリティ特化レンサバ!
関連記事
PHPのcURL関数を使ってHTTPSでアクセスすると環境変数が読込まれる
Apache Tikaを使ってドキュメントの中身を取り出すPHPプログラム
不要なApacheやPHPの拡張モジュールを削除するとどれくらい効果があるか調べてみる
mod_actionsを使ってドキュメントや画像、Flashファイルを保護する
Twitterのお気に入りをTumblrへ投稿するプログラム書いたよ
OAuth経由でTumblrの情報を取得・投稿するPHPスクリプト