Menu
Categories
[PHP] simplexml_load_file и timeout
March 26, 2013 Сеть и интернет

При запросе XML-данных с внешней URL через функцию simplexml_load_file() отсутствует возможность указания максимального времени выполнения (таймаута). В результате при недоступности удаленного ресурса или временных проблемах с доступом к сети могут возникать непредвиденно большие задержки при использовании данной функции.

Простым решением подобной проблемы является возможность запросить XML-данные каким-либо другим средством, предусматривающим возможность настройки таймаутов, после чего передать полученную строку в simplexml_load_string().

Использование file_get_contents+simplexml_load_string

При использовании file_get_contents() для запроса удаленных данных имеется возможность указания ряда параметров при помощи т.н. контекста, создаваемого командой stream_context_create(). Например, указать предельное время ожидания HTTP-запроса можно следующим образом:

$opts = stream_context_create( array(
		'http' => array(
			'timeout' => 1
			)
		) );
$xmlstr = file_get_contents($url, false, $opts);
$xml = @simplexml_load_string($xmlstr);

Либо короче:

$xmlstr = file_get_contents($url, $false, stream_context_create(array('http' => array('timeout' => 1))));
$xml = @simplexml_load_string($xmlstr);

Этот способ работает хорошо до тех пор, пока мы не сталкиваемся с таймаутом при запросе доменного имени $url с DNS. В этом случае выставленный в контексте параметр ‘timeout’ в обработке не участвует и время ожидания по-прежнему может быть слишком высоко.

Использование cURL+simplexml_load_string

Применение библиотеки cURL хотя и требует фактического наличия означенной библиотеки и более громоздко при использовании, но представляет более широкие возможности по настройке параметров соединения:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$xmlstr = curl_exec($ch);
curl_close($ch);
$xml = @simplexml_load_string($xmlstr);

При этом параметром ‘CURLOPT_TIMEOUT’ определяется не только время выполнения запроса, но целиком время выполнения всех операций cURL, включая запросы к DNS. В PHP начиная с версии 5.2.3 поддерживается также параметр ‘CURLOPT_TIMEOUT_MS’, позволяющий указать длительность таймаута в миллисекундах.

Запуск под Windows?

В случае использования apache+php в системе под управлением MS Windows даже при использовании cURL мне не удалось найти никакой действительно работоспособной возможности для обхода длительного таймаута при сбое DNS на стороне локального сервера.

Интересно также, что в принципе запуск модуля cURL (php_curl.dll) в Windows-версии apache по умолчанию происходит с ошибкой, которая в error.log на стороне apache выглядит так:

PHP Warning:  PHP Startup: Unable to load dynamic library 'C:\\php5\\ext\\php_curl.dll' - \xcd\xe5 \xed\xe0\xe9\xe4\xe5\xed \xf3\xea\xe0\xe7\xe0\xed\xed\xfb\xe9 \xec\xee\xe4\xf3\xeb\xfc.\r\n in Unknown on line 0

Либо, при переводе в человеческий вид, так:

PHP Warning:  PHP Startup: Unable to load dynamic library 'C:\\php5\\ext\\php_curl.dll' - Не найден указанный модуль.\r\n in Unknown on line 0

Это, конечно, на редкость информативно и предоставляет возможности для полета фантазии на тему того, о каком именно модуле идет речь. Интересно отметить тот факт, что при запуске php -i модуль cURL загружается корректно, а проблема возникает только при запуске из-под apache.

В описываемом случае проблема отсутствующего модуля решилась путем копирования файлов ‘libeay32.dll’ и ‘ssleay32.dll’ из каталога C:/php5 в каталог C:/apache/bin.

Leave a Reply




*