1. PEAR::HTTP_Clientでサイトの内容取得

他のサイトの内容を取得したいと思ったことはありませんか?PHPで他のサイトの内容を取得する方法はいくつかあります。file_get_contents()を使ったりfsockopen()を使ったりcurlを使ったり。今回はその中からPEARで提供されているPEAR::HTTP_Clientを紹介したいと思います。

このPEAR::HTTP_ClientはHTTP_Requestをラップしたクラスなので、依存しているパッケージがいくつかあります。インストールするときには

pear install --alldeps HTTP_Client

上記のように--alldepsオプションを用いて依存関係にあるパッケージも一緒にインストールすると便利です。

では早速他のサイトの内容を取得してみましょう。ターゲットになるサイトはmixiです。mixiとはもう説明するまでもありませんが、ソーシャルネットワーキングサイトの一つで国内では圧倒的な規模と人気を誇ります。今回はこのmixiにPEAR::HTTP_Clientを使ってアクセスし、マイミクシィ最新日記を取得してみましょう。

下記のスクリプトがそれになります。

<?php
require_once "HTTP/Client.php";

$email "メールアドレス";
$password "パスワード";

$login_params array("next_url" => "/home.pl""email" => $email,
"password" => $password);

$login_url "http://mixi.jp/login.pl";
$new_friend_diary_url "http://mixi.jp/new_friend_diary.pl";

$client =& new HTTP_Client();
$client->post($login_url$login_params);
$client->get($new_friend_diary_url);

$response $client->currentResponse();
preg_match_all("/<td WIDTH=180><img.*?>(.*)<\/td>/"$response['body'],
$date_matches);
preg_match_all("/<td WIDTH=450>(.*)/"$response['body'], $title_matches);

$title "";
foreach (
$title_matches[1] as $key => $value) {
  
$value preg_replace("/view_diary.pl/",
"http://mixi.jp/view_diary.pl"$value);
  
$title .= '<dt>'.$date_matches[1][$key].'</dt><dd>'.$value.'</dd>';
}

print(
'<dl>'.$title.'</dl>');

?>

$emailと$passwordの部分には自身のものをそれぞれ入力してください。実行するとマイミクシィ最新日記が表示されます。

スクリプトの流れを説明すると、まずHTTP_Clientのインスタンスを作成します。次にpost()メソッドでログイン画面のURLとクエリを送信します。次にget()メソッドを使用してマイミクシィ最新日記のURLに飛びcurrentResponse()メソッドでサイトの内容を取得します。後はこの内容をパースして日付とタイトルを取得し表示しています。

以上のように、PEAR::HTTP_Clientを使うと手軽にサイトの内容を取得することができます。この他にもpost()メソッドの第4引数にファイル名等を指定するとファイルのアップロード処理やクッキーのストア、HTTPリダイレクト、リファラの設定等様々なことができます。興味のある方はぜひ使ってみてはいかがでしょ うか。

PEAR::HTTP_Client http://pear.php.net/package/HTTP_Client/

mixi http://mixi.jp/

2. UTF-7とクロスサイト・スクリプティング

UTF-7エンコードの特性を利用したクロスサイト・スクリプティング(UTF-7 XSS)を紹介します。この攻撃はブラウザが出力をUTF-7として認識した場合に生じるものです。日本ではUTF-7は一般的ではありません。しかし、プログラマはこういった文字コードとXSSの関係を把握しておくべきでしょう。

まずは、ブラウザが出力をUTF-7と解釈した場合にJavaScriptが実行されてしまうことを確認しましょう。次のコードをUTF-8等の文字コードで保存し、ブラウザから開いて下さい。

<?php
mb_internal_encoding
('UTF-8');
$str "<script>alert('XSS');</script>";
$str mb_convert_encoding($str'UTF-7');

header("Content-Type: text/html; charset=UTF-7");
echo 
htmlentities($str);
?>

JavaScriptが実行され、アラートでXSSと表示されたと思います。htmlentities()を用いてエスケープ処理をしているにも関わらず、なぜこのようなことが起こるのでしょうか?

その原因は、エスケープ処理をされる文字列のエンコードとブラウザが解釈する文字コード間にズレが生じていることにあります。

まず、出力文字のエンコードですが、コード中で文字列をUTF-7に変換していることに注意して下さい。変換された『<script> alert('XSS');</script>』をUTF-8で出力すると『+ADw-script+AD4-alert('XSS')+ ADsAPA-/script+AD4-』という文字列になります。htmlentities()はこの文字列をUTF-7とは認識していない為にどの部分も変換しません。

しかし、実際にこの文字列がUTF-7と認識された場合、『+ADw-』と『+AD4-』はそれぞれ『<』と『>』と解釈されます。上述のコードでは、header()関数を用いてブラウザに対して文字エンコーディングをUTF-7で指定しています。その為にブラウザは文字列『+ADw- script+AD4-alert('XSS')+ADsAPA-/script+AD4-』を『<script>alert('XSS');</script>』と解釈し、Javascriptを実行してしまいます。

このようなUTF-7 XSSが成立する為には、ブラウザの文字エンコーディングを変更させる必要があります。実際には、PHP内のheaderやHTMLのmetaタグ内で文字セットを指定する部分にユーザ入力が入っていなければ問題にはならないでしょう。

しかしながら、文字コードによってはhtmlentities()等のエスケープ関数でも対応できない場合が存在することを覚えておいて下さい。

3. PHPでYAML

今回はPHPでYAML形式のデータを扱うためのライブラリである「Spyc」について紹介します。

YAMLとは主に記号とインデントで構造を表現し、XMLと比べて読みやすく、編集等が容易になっています。PHPではフレームワークのSymfony等で設定データの定義用にも使用されています。

Spycはsourceforgeにてオープンソース開発されており、YAMLから連想配列へデコード、連想配列からYAMLへのエンコードが非常に簡単に行えます。

まず、以下のサイトからSpycをダウンロードします。

http://spyc.sourceforge.net/(2006年10月現在のバージョンは0.2.3となっています。)

適当なディレクトリに解凍して、includeすれば使用できます。

【YAML→配列変換】
・test.yml
---------------------------------
database:
 real:
  adapter:  mysql
  host:     localhost
  database: phppro
  username: asial
  password: password
 test:
  adapter:  mysql
  host:     localhost
  database: test_phppro
  username: test_asial
  password: test_password
---------------------------------

<?php
require_once('spyc.php');
//Spyc::YAMLLoad(ファイル or YAML文字列);
$array Spyc::YAMLLoad('test.yml');
print_r($array);
?>
---------------------------------
・出力
Array
(
    [database] => Array
        (
            [real] => Array
                (
                    [adapter] => mysql
                    [host] => localhost
                    [database] => phppro
                    [username] => asial
                    [password] => password
                )

            [test] => Array
                (
                    [adapter] => mysql
                    [host] => localhost
                    [database] => test_phppro
                    [username] => test_asial
                    [password] => test_password
                )

        )

)

また、配列をYAMLに変換するには以下のようにします。

【配列→YAML変換】
<?php
require_once('spyc.php');
//Spyc::YAMLDump(配列, インデント, 1行の長さ);
$array array("aaa""bbb"array("ccc""ddd"), "eee" => "fff");
$yaml Spyc::YAMLDump($array,4,60);
print_r($yaml);
?>
・出力
---
- aaa
- bbb
-
    - ccc
    - ddd
eee: fff

このように簡単に、PHPとYAMLの変換ができます。 YAMLファイルを使用する際には、皆さんもぜひ使ってみてはいかがでしょうか。

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。