Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Подгрузка нескольких потоков, Скачиваю сайты 
V
    Опции темы
Levsha
Дата 16.6.2007, 04:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, я уже правда по своему исправил, но все равно спасибо


--------------------
PM   Вверх
Levsha
Дата 19.6.2007, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Столкнулся с такой проблемой, закачивая страницы вышеописанным методом в текст документов иногда вставляются "левые" наборы символов типа: "15f", "25e4", "14bb". Почему это происходит? Может ли это быть некая защита сайтов?

И еще проблема. Как я понимаю, тот же вышеописанный метод использует кеширование? Как его включать и выключать?


--------------------
PM   Вверх
sTa1kEr
Дата 19.6.2007, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Levsha @  19.6.2007,  16:03 Найти цитируемый пост)
Столкнулся с такой проблемой, закачивая страницы вышеописанным методом в текст документов иногда вставляются "левые" наборы символов типа: "15f", "25e4", "14bb". Почему это происходит? Может ли это быть некая защита сайтов?

Надо разбираться на конкретном примере.
Цитата(Levsha @  19.6.2007,  16:03 Найти цитируемый пост)
И еще проблема. Как я понимаю, тот же вышеописанный метод использует кеширование? Как его включать и выключать?

Нет, кэширование не используется. Где вы это увидели?
PM MAIL   Вверх
Levsha
Дата 19.6.2007, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата(sTa1kEr @  20.6.2007,  00:49 Найти цитируемый пост)
Нет, кэширование не используется. Где вы это увидели?
Да просто браузер выдал одно, а сервер скачал другое...

Добавлено через 12 минут и 11 секунд
Цитата(sTa1kEr @  20.6.2007,  00:49 Найти цитируемый пост)
Надо разбираться на конкретном примере.
Ну например если скачивать сайт с запросом: http://www.service-whois.ru/?domain=mail.ru получаю баги (на скриншоте)

sTa1kEr, проверьте пожалуйста, может это только у меня глючит.

Что примечательно, для http://www.service-whois.ru/?domain=yandex.ru такого нет.

Присоединённый файл ( Кол-во скачиваний: 18 )
Присоединённый файл  1.gif 15,04 Kb


--------------------
PM   Вверх
sTa1kEr
Дата 19.6.2007, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Levsha, попробую вечером разобраться.
Цитата(Levsha @  19.6.2007,  17:57 Найти цитируемый пост)
sTa1kEr, проверьте пожалуйста, может это только у меня глючит.

Нет, у меня тоже самое, только символы другие.
PM MAIL   Вверх
teroni
Дата 20.6.2007, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 15.5.2007
Где: Днепропетровск

Репутация: 1
Всего: 22



Да, сталкивался с такой же проблемой...
Из-за чего возникает - так и не понял, для решения - тупо обрезал все, до первого < и после последнего >. Мне кажется, что это каким-то образом зависит от хостинга, на котором расположена скачиваемая страница, т.к. на некоторых такая проблема не возникает.

Это сообщение отредактировал(а) teroni - 20.6.2007, 11:14
PM MAIL   Вверх
sTa1kEr
Дата 20.6.2007, 17:04 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Разобрался в чем дело. Достаточно было повнимательнее почитать спецификацию HTTP 1.1 smile 3.6.1 Chunked Transfer Coding
Смысл этого хидера в крации: Для лучшего контроля передачи данных в HTTP 1.1 существует возможность передавать контент по частям с указанием размера каждой части. Сначала передается размер следующего блока (число в HEX и следующий за ним разделитель строки CRLF), затем сам блок и так далее пока размер блока не будет равен нулю (0 в самом конце). Я вижу три способа решения этой проблемы:
1. Опять же самое простое. Вместо HTTP 1.1 использовать HTTP 1.0.
2. Сначала получаем хидеры. Смотрим используется ли Chunked Coding (заголовок Transfer-Encoding: chunked). Если используется то полученный контент декодируем при помощи http://ru2.php.net/manual/ru/function.http...nked-decode.php. Но для этого придется установить соответствующее PECL расширение.
3. Имхо, самое правильное. Если предоставляется возможность дополнительного контроля целостности данных, то почему бы этим не воспользоваться? 
Код

function get_chanked($stream)
{
   $content = "";
   do
   {
      $len = trim(fgets($stream, 10));
      if (MD_DEBUG) echo "Find lable 0x$len<br>\n";
      if ($len === false || !preg_match("|[0-9a-f]+|i", $len))
      {
         if (MD_DEBUG) echo "Failure getting content<br>\n";
         return "";
      }
      else
      {
         $len = hexdec($len);
         if (MD_DEBUG) echo "Reading $len byte<br>\n";
      }
      if ($len > 0)
      {
         $readed = 0;
         while($readed < $len + 2)
         {
            $buffer = fgets($stream);
            $readed += strlen($buffer);
            $content .= $buffer;
         }
      }
   } while($len > 0);
   return $content;
}

Соответственно в функции MyDownload при чтении будет:
Код

          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $isChunk = false;
                $result[$url] = "";
                while(($header = fgets($read)) != "\r\n")
                {
                   if (preg_match("|Transfer-Encoding:\s+chunked|i", $header))
                   {
                      $isChunk = true;
                   }
                }
                if ($isChunk)
                {
                   $result[$url] = get_chanked($read);
                }
                else
                {
                   while (!feof($read))
                   {
                      $result[$url] .= fread($read, 1024); 
                   }
                }
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }


Это сообщение отредактировал(а) sTa1kEr - 20.6.2007, 17:58
PM MAIL   Вверх
Levsha
Дата 21.6.2007, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Вот уж действительно раздел для профи...
Пытаюсь подстроить в свое...
Отпишусь...


--------------------
PM   Вверх
Levsha
Дата 21.6.2007, 08:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Есть, срабатывает шикарно, ошибок нет. Щас еще чутка доделаю-приделаю и выложу свою версию smile 
sTa1kEr, мегаспасибо


--------------------
PM   Вверх
Levsha
Дата 21.6.2007, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



В общем если нужно - моя версия:
Код

if (!defined("MD_DEBUG")) define("MD_DEBUG", false);
function get_chanked($stream) {
   $content = "";
   do
   {
      $len = trim(fgets($stream, 10));
      if (MD_DEBUG) echo "Find lable 0x$len<br>\n";
      if ($len === false || !preg_match("|[0-9a-f]+|i", $len))
      {
         if (MD_DEBUG) echo "Failure getting content<br>\n";
         return "";
      }
      else
      {
         $len = hexdec($len);
         if (MD_DEBUG) echo "Reading $len byte<br>\n";
      }
      if ($len > 0)
      {
         $readed = 0;
         while($readed < $len + 2)
         {
            $buffer = fgets($stream);
            $readed += strlen($buffer);
            $content .= $buffer;
         }
      }
    } while($len > 0);
    return $content;
    }

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $host = parse_url($url, PHP_URL_HOST);
       if ($host === null)
       {
          if (MD_DEBUG) echo "Host in '$url' is not correct<br>\n";
          continue;
       }
       $port = parse_url($url, PHP_URL_PORT);
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$host:".($port === null ? "80" : $port),
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          if (MD_DEBUG) echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = @stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                $host = parse_url($url, PHP_URL_HOST);
                $request = "GET $url HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $host\r\nConnection: Close\r\n\r\n";
                if (MD_DEBUG) echo "Sending request for $url<br>\n$request";
                fwrite($write, $request);
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                $key = array_keys ($urls, $url); $key = $key[0];
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $isChunk = false;
                $charset = "";
                $result[$key][0] = "";
                while(($header = fgets($read)) != "\r\n") {
                    if (!(strpos($header, "Content-Type")===false)) if (!(strpos($header, "charset=")===false)) $charset = substr($header, strpos($header, "charset=")+8);
                    else $charset = "default";
                    if (preg_match("|Transfer-Encoding:\s+chunked|i", $header)) $isChunk = true;
                 }
                if ($isChunk) $result[$key][0] = get_chanked($read);
                else while (!feof($read)) $result[$key][0] .= fread($read, 1024);
                $result[$key][1] = $charset;
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                if (MD_DEBUG) echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

$urls = array(
"yandex"=>"http://www.yandex.ru/yandsearch?text=Превед",
"whois"=>"http://www.service-whois.ru/?domain=mail.ru"
    );
$sites = MyDownload ($urls);
$yandex1 = $sites["yandex"][0];
$yandex2 = $sites["yandex"][1];

Основное отличие в том, что дается функции двумерный массив, а возвращается массив содержащий тело документа[0] и кодировку[1]. В принципе туда легко можно добавить любую другую информацию...


--------------------
PM   Вверх
Levsha
Дата 24.6.2007, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



А вот и новая проблема, если один из скачиваемых сайтов не отвечает долгое время, т.е. вообще нет ответа от сервера, ни ошибки, ничего другого, то останавливается все, соответственно сайт встает. Возможно ли установить лимит по времени на ответ сервера, чтобы по истечении возвращалась бы пустая строка или что-то вроде... Ну в общем лишь бы сайт не вставал.


--------------------
PM   Вверх
Levsha
Дата 25.6.2007, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



У меня ощущение что $timeout не работает.. Я так понимаю, $timeout=30 подразумевает секунды? А страница прогружается за пять секунд, не выдав никакого результута...

Есть соображения у кого?


--------------------
PM   Вверх
sTa1kEr
Дата 25.6.2007, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Странно... Если хоста не существует, то поток не будет создан. А если будет ошибка, то он попадет в массив $eStreams и будет благополучно выброшен. Можете привести пример хоста из-за которого он зацикливается?
Цитата(Levsha @  25.6.2007,  10:22 Найти цитируемый пост)
У меня ощущение что $timeout не работает.. Я так понимаю, $timeout=30 подразумевает секунды? А страница прогружается за пять секунд, не выдав никакого результута...

$timeout - это таймаут только для соединения с сервером. Т.ч. вполне возможно, что он законнектиться с сервером за 5 секунд и тут же сервер вернет ошибку.
PM MAIL   Вверх
Levsha
Дата 25.6.2007, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Хост существует, просто он долго думает что ответить... Ну это в прошлом...

Сейчас просто если я делаю закачку 11 требуемых документов, то происходит ошибка, причем на удаленном сервере он вообще не выдает ошибки, просто работа приостанавливается, даже при включенном error_reporting и display_errors.

А локально выдается
Код

Fatal error: Maximum execution time of 30 seconds exceeded in y:\home\...\func.php on line 301


А 301я строка - это первая строка цикла:
Код

while(($header = fgets($read)) != "\r\n") {
   if (!(strpos($header, "Content-Type")===false)) if (!(strpos($header, "charset=")===false)) $charset = substr($header, strpos($header, "charset=")+8);
   else $charset = "default";
   if (preg_match("|Transfer-Encoding:\s+chunked|i", $header)) $isChunk = true;
}


Добавлено @ 15:30
Можно ли сделать, чтобы он вообще если не успел ниче за 30 сек, то пусть вообще пустые строки вернет.

Это сообщение отредактировал(а) Levsha - 25.6.2007, 15:30


--------------------
PM   Вверх
sTa1kEr
Дата 25.6.2007, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Levsha @  25.6.2007,  15:27 Найти цитируемый пост)
А 301я строка - это первая строка цикла:

Хм, сервер вернул контент без хидера или просто скрипт не успел все скачать. Попробуйте увеличьте максимальное время работы скрипта.
Код

set_time_limit(90); 

И добавьте проверку
Код

while(($header = fgets($read)) !== false && $header != "\r\n")

Цитата(Levsha @  25.6.2007,  15:27 Найти цитируемый пост)
Можно ли сделать, чтобы он вообще если не успел ниче за 30 сек, то пусть вообще пустые строки вернет.

В этом мире нету ничего невозможного. В начале функции в переменную запишите метку времени и добавьте в цикл условие. Можно добавить в цикл для чтения данных такую же проверку. Можно воспользоваться register_shutdown_function(), но тогда при таймауте не удастся вывести ничего в браузер.
Код

$endWork = mktime() + 30;
// ...
do
{
// ...
} while(count($toRead) > 0 && mktime() < $endWork);


Это сообщение отредактировал(а) sTa1kEr - 25.6.2007, 16:16
PM MAIL   Вверх
Страницы: (4) Все 1 [2] 3 4 
Ответ в темуСоздание новой темы Создание опроса

Внимание: данный раздел предназначен для решения сложных, нестандартных задач.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Для профи | Следующая тема »


 




[ Время генерации скрипта: 0.0973 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.