file_get_contents vs CURL
Сегодня столкнулся с проблемой: file_get_contents НЕ использовал указанный мной таймаут для чтение удаленного файла.. Проблема оказалась для меня не столь очевидной, т.к. я её сразу не смог повторить, да что там повторить, я не сразу понял вообще в чем проблема..
Прежде всего было замечено, что скрипт не всегда завершается так, как должен. Я начал дебажить скрипт, и вскоре увидел, что проблема возникает именно в загрузке файлов.
Код для обработки был примерно вот такой:
1 2 3 4 5 6 |
$data = @file_get_contents($url, false, stream_context_create(array('http'=>array( 'method' => 'GET', 'timeout' => 30, )))); |
Во-первых @ помогла пропустить ошибку, но тут её использование было оправдано, т.к. допускались 404 ошибки, и было необходимо их не писать в логи, а в $data передавать false.
После проведения мной нескольких тестов, оказалось, что file_get_contents попросту не реагирует на указанный мной таймаут, как я думал, это таймаут на соединения И на закачку url...
Я полез в Google и он меня вывел на StackOverflow, вот сюда: PHP file_get_contents ignoring timeout?
Там обсуждалась точно такая же проблема и ей дали объяснение:
You are setting the read timeout with
socket_create_context
. If the page you are trying to access doesn't exist then the server will let you connect and give you a 404. However, if the site doesn't exist (won't resolve or no web server behind it), thenfile_get_contents()
will ignore read timeout because it hasn't even timed out connecting to it yet.
Вкратце тут говорится, что в случае, если сайт не существует, то file_get_contents игнорирует(!) указанный таймаут, т.к. происходит НЕ таймаут приема данных, а тайм аут соединения с сервером. А file_get_contents НЕ обрабатывает его.
В таких случаях, некоторые советуют менять таймаут сокета:
1 2 3 |
<?php ini_set('default_socket_timeout', 5); ?> |
однако это не приведет к ожидаемому эффекту, т.к. эта настройка служит для работы с медленными соединениями и не имеет отношения к описанной проблеме.
Что же делать?
Можно воспользоваться функцией: fsockopen, одним из параметров которой является именно тайм-аут соединения. Как её использовать, это уже ваше дело: можно просто проверить сайт на существование, перед использованием file_get_contents. А можно написать свой file_get_contents используя сокеты. Не так уж это и сложно..
Я же выбираю другой вариант, а именно библиотеку CURL, где все это уже реализовано. Так же советую этот метод и Вам. Код получится примерно такой:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private function download_file_from_www($url, $connect_timeout=10, $timeout=120) { $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_TIMEOUT, $timeout); curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, $connect_timeout); $data = curl_exec($ch); curl_close($ch); return $data; } |
Здесь нет ничего военного: CURLOPT_TIMEOUT = задает время за которое мы должны загрузить указанный url, а CURLOPT_CONNECTTIMEOUT = задает время на соединение с сервером. Почитать подробнее про параметры можно тут: curl_setopt
Вместо вывода: часто (например, в прототипах) я ленюсь сразу писать нужный код, ведь куда проще написать 1 строчку (file_get_contents) вместо целого метода (CURL или сокеты). Однако как показывает практика, если есть сомнения, лучше потратить сразу 5 минут на написание "правильного метода", чем потом несколько часов вылавливать совсем не очевидный баг. В любом случае, очередная проблема решена, опыт прокачан - УРА!!!!!!
Author: | Tags: /
| Rating:
Leave a Reply