| PHPのちょっとしたTIPS |
| Last Modified : 2003/03/18 (Tue) |
| No.3 | HTTPクライアント - fsockopen() fputs() fgets() fclose() parse_url() urlencode() |
|
PHPで簡易HTTPクライアントを作ってみます。 とりあえず、TELNETを使って実際にWEBサーバと通信してみます。 基本は $ telnet ホスト名 ポート番号 です。 Windowsのtelnet.exeでも同じようにできます。 ローカルエコーがオン、改行コードは<CRLF>である必要があります。 TeraTermを使う時もそこら辺を設定しておく必要があります。 以下はLinux上で行っています。改行は<CRLF>と書いてます。 ローカルでApacheを起動しておいて、 $ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]' GET / HTTP/1.0<CRLF> <CRLF> HTTP/1.1 200 OK Date: Mon, 18 Jun 2001 12:46:47 GMT Server: Apache/1.3.20 (Unix) PHP/4.0.5 PHP/3.0.18-i18n-ja-2 X-Powered-By: PHP/4.0.5 Connection: close Content-Type: text/html; charset=shift_jis (省略) Connection closed by foreign host.という感じです。 GET / HTTP/1.0 という一行は Request-Line というやつで、 Method Request-URI HTTP-Version<CRLF> というフォーマットです。 Methodはいろいろありますが、GET、POST、HEADぐらいは知っておきましょう。 一般にWEBサーバへのRequestは、 Request-Line<CRLF> Request-Header<CRLF> <CRLF> Message-Bodyという形です。 Request-HeaderにはRefererとかUser-Agentとかのヘッダを記入します。 ヘッダ名:値<CRLF> という感じでコロンで区切ります。 Message-BodyはPOSTメソッドのようにサーバへデータを送るときに使います。 というわけでfsockopen()関数を使って作ってみました。(笑) HEAD, GET, POSTで動きます。Basic認証もいけます。
<?php
/*
$url : http://から始まるURL( http://user:pass@host:port/path?query )
$method : GET, POST, HEADのいずれか(デフォルトはGET)
$headers : 任意の追加ヘッダ
$post : POSTの時に送信するデータを格納した配列("変数名"=>"値")
*/
function http($url, $method="GET", $headers="", $post=array(""))
{
/* URLを分解 */
$URL = parse_url($url);
/* クエリー */
if (isset($URL['query'])) {
$URL['query'] = "?".$URL['query'];
} else {
$URL['query'] = "";
}
/* デフォルトのポートは80 */
if (!isset($URL['port'])) $URL['port'] = 80;
/* リクエストライン */
$request = $method." ".$URL['path'].$URL['query']." HTTP/1.0\r\n";
/* リクエストヘッダ */
$request .= "Host: ".$URL['host']."\r\n";
$request .= "User-Agent: PHP/".phpversion()."\r\n";
/* Basic認証用のヘッダ */
if (isset($URL['user']) && isset($URL['pass'])) {
$request .= "Authorization: Basic ".base64_encode($URL['user'].":".$URL['pass'])."\r\n";
}
/* 追加ヘッダ */
$request .= $headers;
/* POSTの時はヘッダを追加して末尾にURLエンコードしたデータを添付 */
if (strtoupper($method) == "POST") {
while (list($name, $value) = each($post)) {
$POST[] = $name."=".urlencode($value);
}
$postdata = implode("&", $POST);
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: ".strlen($postdata)."\r\n";
$request .= "\r\n";
$request .= $postdata;
} else {
$request .= "\r\n";
}
/* WEBサーバへ接続 */
$fp = fsockopen($URL['host'], $URL['port']);
/* 接続に失敗した時の処理 */
if (!$fp) {
die("ERROR\n");
}
/* 要求データ送信 */
fputs($fp, $request);
/* 応答データ受信 */
$response = "";
while (!feof($fp)) {
$response .= fgets($fp, 4096);
}
/* 接続を終了 */
fclose($fp);
/* ヘッダ部分とボディ部分を分離 */
$DATA = split("\r\n\r\n", $response, 2);
/* リクエストヘッダをコメントアウトして出力 */
echo "<!--\n".$request."\n-->\n";
/* レスポンスヘッダをコメントアウトして出力 */
echo "<!--\n".$DATA[0]."\n-->\n";
/* メッセージボディを出力 */
echo $DATA[1];
}
?>
改行コードは<CRLF>だからPHPでは"\r\n"です。parse_url()関数は便利ですね。 URLを各要素に分解して連想配列を返します。ここではこれを利用しました。 Basic認証用のAuthorizationヘッダはユーザ名とパスワードをコロンで区切ってbase64_encode()するだけです。単純ですね。 POSTメソッドでは、Content-TypeヘッダとContent-Lengthヘッダを付加してメッセージボディとしてurlencode()したデータを添付します。 サーバからのレスポンスはヘッダとメッセージボディが<CRLF><CRLF>で区切られているので、split()関数で分割しました。 (単に出力するだけならその必要もないですけど) クッキーを与えたい時はCookieヘッダを作ってあげればOKです。その他任意のヘッダを引数に指定できます。デフォルトでHostヘッダとUser-Agentヘッダを送信します。 使い方は簡単です。普通にGETするだけなら、
<?php
http("http://www.spencernetwork.org/");
?>
です。とはいえ、このままだと実用的ではないので実験用ですね(^^; |
|