Главная > PHP | Бездна > file_get_contents vs CURL

file_get_contents vs CURL

02.02.2013 0 коммент. » Просмотры: 5 038
 

Сегодня столкнулся с проблемой: file_get_contents НЕ использовал указанный мной таймаут для чтение удаленного файла.. Проблема оказалась для меня не столь очевидной, т.к. я её сразу не смог повторить, да что там повторить, я не сразу понял вообще в чем проблема..

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

Код для обработки был примерно вот такой:

$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), then file_get_contents() will ignore read timeout because it hasn't even timed out connecting to it yet.

Вкратце тут говорится, что в случае, если сайт не существует, то file_get_contents игнорирует(!) указанный таймаут, т.к. происходит НЕ таймаут приема данных, а тайм аут соединения с сервером. А file_get_contents НЕ обрабатывает его.

В таких случаях, некоторые советуют менять таймаут сокета:

<?php ini_set('default_socket_timeout', 5); ?>

однако это не приведет к ожидаемому эффекту, т.к. эта настройка служит для работы с медленными соединениями и не имеет отношения к описанной проблеме.

 

Что же делать?

Можно воспользоваться функцией: fsockopen, одним из параметров которой является именно тайм-аут соединения. Как её использовать, это уже ваше дело: можно просто проверить сайт на существование, перед использованием file_get_contents. А можно написать свой file_get_contents используя сокеты. Не так уж это и сложно..

Я же выбираю другой вариант, а именно библиотеку CURL, где все это уже реализовано. Так же советую этот метод и Вам. Код получится примерно такой:

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 минут на написание "правильного метода", чем потом несколько часов вылавливать совсем не очевидный баг. В любом случае, очередная проблема решена, опыт прокачан - УРА!!!!!!

 

Автор: | Теги: ,

Важно

У нас заработал ФОРУМ. Все вопросы, которые не касаются статьи, а так же вопросы по конкретно вашему случаю нужно задавать и обсуждать именно там, в разделе "Помощь пользователям".

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Разрешены HTML-теги: <a>, <code>, <i>, <em>, <strong>, <b>, <u>, <strike>