Статьи

десериализовать Yahoo! результаты поиска

Через Джона Кокса , Yahoo! открыли Центр разработки PHP для своих поисковых API и, что более интересно, начали представлять свои поисковые данные как сериализованные строки PHP. Это «сериализовано», как в функции сериализации .

Это очень круто, но думаю, что при его использовании необходимо соблюдать осторожность, учитывая, что он предназначен не для проводного формата, а для локального хранения данных PHP в доверенной среде.

Этот формат безопасен?

Во-первых, это проблема доверия и, возможно, проблема безопасности. Я думаю, мы можем доверять Yahoo! Хорошо, но им нужно быть уверенными в том, что они избегают данных, которые они публикуют таким образом, правильно — убедитесь, что никто, для кого они собрали результаты поиска, не сможет внедрить туда что-либо. Почему?

Что касается примитивных типов данных (строк, int, PHP-массивов), то здесь более или менее нет проблем — вы можете десериализовать полученный результат без проблем. Тем не менее, возможно, проекту Hardened-PHP нужно посмотреть на это — есть ли такие проблемы, как глубоко вложенные массивы, бесконечная рекурсия или очень большие структуры данных?

Однако потенциальная проблема безопасности (но с низким уровнем риска) заключается в том, если какие-либо объекты сериализуются таким образом. Когда вы десериализуете, PHP попытается создать экземпляры этих объектов (при условии, что он может найти соответствующий класс), что приведет к увольняют строителя функция __wakeup, если таковая существует в определении класса, и деструктор в PHP5 , Учитывая, что в PHP5 растет все больше встроенных классов, есть вероятность, что это может стать серьезной проблемой.

Я имел дело с этим раньше в JPSpan , который также использовал этот формат по сети, и упомянул об этом Джошу здесь . Решение, которое я выбрал, состояло в том, чтобы сначала просмотреть сериализованную строку с некоторыми регулярными выражениями, и я на 99% уверен, что этот подход работает — реализация здесь ( JPSpan_Unserializer_PHP::getClasses ) и модульные тесты здесь — см. TestOfJPSpan_Unserializer_PHP_getClasses .

Для Yahoo !, это сделает следующая функция;

function hasObjects($string) { // Stip any string representations (which might contain object syntax) $string = preg_replace('/s:[0-9]+:".*"/Us','',$string); // Pull out the class named preg_match_all('/O:[0-9]+:"(.*)"/U',$string,$matches,PREG_PATTERN_ORDER); return count($matches[1]) > 0; } $serializedString = file_get_contents('http://api.search.yahoo.com ... (etc.) ... &output=php'); if ( hasObjects($serializedString) ) { die ("Its got objects. I object!"); } $result = unserialize($serializedString);
function hasObjects($string) { // Stip any string representations (which might contain object syntax) $string = preg_replace('/s:[0-9]+:".*"/Us','',$string); // Pull out the class named preg_match_all('/O:[0-9]+:"(.*)"/U',$string,$matches,PREG_PATTERN_ORDER); return count($matches[1]) > 0; } $serializedString = file_get_contents('http://api.search.yahoo.com ... (etc.) ... &output=php'); if ( hasObjects($serializedString) ) { die ("Its got objects. I object!"); } $result = unserialize($serializedString); 

Учитывая, что большинство людей будут получать эти данные из Yahoo! в открытом тексте есть шанс, что злоумышленник сможет изменить его при передаче, поэтому вызов этой функции для проверки объектов, вероятно, является разумным шагом.

Кодировка символов?

Теперь Yahoo! был умным в кодировании данных как UTF-8. Вот заголовки HTTP-ответа на сделанный мной запрос (примечание: возможно, Yahoo! может немного подумать об использовании HTTP-кэширования, учитывая, что это REST?);

HTTP/1.x 200 OK Date: Thu, 23 Feb 2006 08:14:38 GMT P3p: policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="[snip]" Connection: close Content-Type: text/php; charset="utf-8"
HTTP/1.x 200 OK Date: Thu, 23 Feb 2006 08:14:38 GMT P3p: policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="[snip]" Connection: close Content-Type: text/php; charset="utf-8" 

Проверено с некоторыми многобайтовыми результатами, и Yahoo правильно считает многострочные длины в байтах в результатах PHP, которые они возвращают, так что никаких проблем нет. Вам, вероятно, нужно знать, какую кодировку вы используете на сайте, где отображаются результаты. Джон , например, использует ISO-8859-1 (что очень распространено), поэтому вы захотите преобразовать UTF-8 в ISO-8859-1, используя utf8_decode (который предназначен исключительно для использования с ISO-8859-1! ) на элементах данных, после вызова unserialize (). Люди с более экзотическими кодировками символов должны будут обратиться к iconv . В Firefox откройте страницу на своем сайте, щелкните правой кнопкой мыши и выберите «Информация о странице» — это сообщит вам кодировку вашего персонажа.

Пример с PEAR :: HTTP_Request

Yahoo! приведите примеры с curl и file_get_contents () . Вот альтернативный пример использования PEAR :: HTTP_Request ;

< ?php // Include PEAR::HTTP_Request require_once 'HTTP/Request.php'; // Something to search for $searchword = 'Zürich'; // Build Yahoo! web search URL $yahoo_url = 'http://api.search.yahoo.com/WebSearchService'. '/V1/webSearch?appid=YahooDemo&results=10&output=php'. '&query='.$searchword; // Create the HTTP_Request object, specifying the URL $Request = &new HTTP_Request($yahoo_url); // Set proxy server as necessary // $Request->setProxy('proxy.myisp.com', '8080', 'harryf', 'secret'); // Send the request for the feed to the remote server $status = $Request->sendRequest(); // Check for errors if (PEAR::isError($status)) { // Do something friendlier than die... die("Connection problem: " . $status->toString()."<br />"); } // Check we got an HTTP 200 status code (if not there's a problem) if ($Request->getResponseCode() != '200') { // Do something friendlier than die... die("Request failed: " . $Request->getResponseCode()."<br />"); } // Get the PHP serialized string from Yahoo! $phps = $Request->getResponseBody(); // Function to test that the serialized string doesn't contain any objects function hasObjects($string) { // Stip any string representations (which might contain object syntax) $string = preg_replace('/s:[0-9]+:".*"/Us','',$string); // Pull out the class named preg_match_all('/O:[0-9]+:"(.*)"/U',$string,$matches,PREG_PATTERN_ORDER); return count($matches[1]) > 0; } // Check this before unserializing if ( hasObjects($phps) ) { // Do something friendlier than die... die("Serialized string contains objects<br />"); } // Unserialize... $data = unserialize($phps); // Note the charset! header('Content-type: text/html; charset=utf-8'); echo '<pre>'; foreach ( $data['ResultSet']['Result'] as $row ) { print_r($row); } echo '</pre>'; для < ?php // Include PEAR::HTTP_Request require_once 'HTTP/Request.php'; // Something to search for $searchword = 'Zürich'; // Build Yahoo! web search URL $yahoo_url = 'http://api.search.yahoo.com/WebSearchService'. '/V1/webSearch?appid=YahooDemo&results=10&output=php'. '&query='.$searchword; // Create the HTTP_Request object, specifying the URL $Request = &new HTTP_Request($yahoo_url); // Set proxy server as necessary // $Request->setProxy('proxy.myisp.com', '8080', 'harryf', 'secret'); // Send the request for the feed to the remote server $status = $Request->sendRequest(); // Check for errors if (PEAR::isError($status)) { // Do something friendlier than die... die("Connection problem: " . $status->toString()."<br />"); } // Check we got an HTTP 200 status code (if not there's a problem) if ($Request->getResponseCode() != '200') { // Do something friendlier than die... die("Request failed: " . $Request->getResponseCode()."<br />"); } // Get the PHP serialized string from Yahoo! $phps = $Request->getResponseBody(); // Function to test that the serialized string doesn't contain any objects function hasObjects($string) { // Stip any string representations (which might contain object syntax) $string = preg_replace('/s:[0-9]+:".*"/Us','',$string); // Pull out the class named preg_match_all('/O:[0-9]+:"(.*)"/U',$string,$matches,PREG_PATTERN_ORDER); return count($matches[1]) > 0; } // Check this before unserializing if ( hasObjects($phps) ) { // Do something friendlier than die... die("Serialized string contains objects<br />"); } // Unserialize... $data = unserialize($phps); // Note the charset! header('Content-type: text/html; charset=utf-8'); echo '<pre>'; foreach ( $data['ResultSet']['Result'] as $row ) { print_r($row); } echo '</pre>';
< ?php // Include PEAR::HTTP_Request require_once 'HTTP/Request.php'; // Something to search for $searchword = 'Zürich'; // Build Yahoo! web search URL $yahoo_url = 'http://api.search.yahoo.com/WebSearchService'. '/V1/webSearch?appid=YahooDemo&results=10&output=php'. '&query='.$searchword; // Create the HTTP_Request object, specifying the URL $Request = &new HTTP_Request($yahoo_url); // Set proxy server as necessary // $Request->setProxy('proxy.myisp.com', '8080', 'harryf', 'secret'); // Send the request for the feed to the remote server $status = $Request->sendRequest(); // Check for errors if (PEAR::isError($status)) { // Do something friendlier than die... die("Connection problem: " . $status->toString()."<br />"); } // Check we got an HTTP 200 status code (if not there's a problem) if ($Request->getResponseCode() != '200') { // Do something friendlier than die... die("Request failed: " . $Request->getResponseCode()."<br />"); } // Get the PHP serialized string from Yahoo! $phps = $Request->getResponseBody(); // Function to test that the serialized string doesn't contain any objects function hasObjects($string) { // Stip any string representations (which might contain object syntax) $string = preg_replace('/s:[0-9]+:".*"/Us','',$string); // Pull out the class named preg_match_all('/O:[0-9]+:"(.*)"/U',$string,$matches,PREG_PATTERN_ORDER); return count($matches[1]) > 0; } // Check this before unserializing if ( hasObjects($phps) ) { // Do something friendlier than die... die("Serialized string contains objects<br />"); } // Unserialize... $data = unserialize($phps); // Note the charset! header('Content-type: text/html; charset=utf-8'); echo '<pre>'; foreach ( $data['ResultSet']['Result'] as $row ) { print_r($row); } echo '</pre>'; 

Не только PHP

Кодеры и декодеры для этого формата были сделаны на нескольких языках. Некоторые, о которых я знаю;

Перемещение по закодированному SOAPtext/php берет верх 🙂