curl(curl_multi) で PEAR_Error 対処
エラー
No unserialized data available. Use XML_Unserializer::unserialize() first.
対策
以下2つの対策をとった。(2011/5/6 もうひとつ追記)
backtrace 省略
エラーになったときに膨大な backtrace が返却される。
その膨大さが何か影響してFatalで落としたくないし、JS側へ返却するのに膨大な不要データはいらない。
そこでbacktraceを省略させる。
@see http://blog.koshigoe.jp/mt-search.cgi?IncludeBlogs=3&tag=pear&limit=20
require_once 'PEAR.php';
$isSkiptrace = &PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
$isSkiptrace = true;
レスポンスデータの文字コード強制変換
想定外の文字コードとしてXMLのパースが落ちているようなので、強制的にUTF-8とするようにした。
@see http://moviesearch1.blog15.fc2.com/blog-entry-7.html
/* * $dはURLとかが入っているものとする */ // result data $result = array(); // array of curl_multi handles $ha = array(); // curl_multi handle $mh = curl_multi_init(); // // set // for ($i=0,$l=count($d); $i<$l; $i++) { $p = $d[$i]; // initialize $ha[$p['name']] = curl_init($p['url']); // set options curl_setopt($ha[$p['name']], CURLOPT_HEADER, 0); curl_setopt($ha[$p['name']], CURLOPT_RETURNTRANSFER, 1); curl_setopt($ha[$p['name']], CURLOPT_TIMEOUT, 1); // timeout(sec) // add curl_multi_add_handle($mh, $ha[$p['name']]); } // // execute // $running = null; do { curl_multi_exec($mh, $running); } while($running); // get content and remove handles foreach($ha as $name => $c) { // confirm status $status = curl_getinfo($ha[$name]); // expected status code of 2xx if ( substr($status['http_code'], 0, 1) == '2' ) { $Unserializer = new XML_Unserializer(); $Unserializer->setOption('parseAttributes',TRUE); $xml = curl_multi_getcontent($c); // ここで強制的に文字コードを変換 $xml = mb_convert_encoding($xml, "UTF-8", "auto"); if ( $status = $Unserializer->unserialize( $xml ) ) { $result[$name] = $Unserializer->getUnserializedData(); } curl_multi_remove_handle($mh, $c); } } // all done curl_multi_close($mh);
2011/5/6 追記 データサイズと実行時間について
海外のホスティングでプログラムを実行した際に同様のエラーが発生した。
問題を確認すると、どうもcurlで取得しているデータが不完全な状態で終わっている。
原因としてはcurl_multiのオプション指定で、許容実行時間内でデータの取得が終わらなかったことによるものだった。
// curlの実行時間を1秒する //curl_setopt($ha[$p['name']], CURLOPT_TIMEOUT, 1); // 上記では取得途中で切断するものがあったため3秒に伸ばす curl_setopt($ha[$p['name']], CURLOPT_TIMEOUT, 3);
で
エラーが無くなったきがする。