PHP Proxy Checker (curl_multi)

Поступил заказ на реализацию простого прокси чекера на php. Особых требований нету, только одно - количество прокси от 60к штук o_O, от чего я вошёл в небольшой ступор.

Начал реализацию через обычный curl и мускул. В процессе тестирования стало ясно что ждать результатов в этом году уже нам не придется :) И я начал курить гугль по тематике много поточности.

Много поточности в php нету и наверное не будет. Есть только извращенные методы эмуляции, которые дают результат, но далеко не идеальный.

Короче, не стал я забивать голову процессами, сокетами, сторонними модулями и тд, а начал ковырять curl_multi который позволяет делать POST GET HEAD запросы в несколько потоков и не только.

Много реализаций перелопатил, облазил много форумов блогов и в результате создал как мне кажется "правильный код" который делает то что мне нужно. Давайте рассмотрим код в деталях:


1. Открываем файлик с проксиками proxies
  1. $proxies = file ("proxies.txt");
2. Создаем мультикурл и получаем его хендл
  1. $mc = curl_multi_init ();
3. Создаем n сеансов curl и записываем дескрипторы в массив $c. Позже все эти курлы мы запустим параллельно :). Каждый сеанс инициализируется своим прокси (см. CURLOPT_PROXY) и своими тамаутами (CURLOPT_CONNECTTIMEOUT - таймаут конекта и CURLOPT_TIMEOUT - тамаут на скачивание контента).
  1. for ($thread_no = 0; $thread_no<count ($proxies); $thread_no++)
  2.  {
  3.   $c [$thread_no] = curl_init ();
  4.   curl_setopt ($c [$thread_no], CURLOPT_URL, "http://google.com");
  5.   curl_setopt ($c [$thread_no], CURLOPT_HEADER, 0);
  6.   curl_setopt ($c [$thread_no], CURLOPT_RETURNTRANSFER, 1);
  7.   curl_setopt ($c [$thread_no], CURLOPT_CONNECTTIMEOUT, 5);
  8.   curl_setopt ($c [$thread_no], CURLOPT_TIMEOUT, 10);
  9.   curl_setopt ($c [$thread_no], CURLOPT_PROXY, trim ($proxies [$thread_no]));
  10.   curl_setopt ($c [$thread_no], CURLOPT_PROXYTYPE, 0);
  11.   curl_multi_add_handle ($mc, $c [$thread_no]);
  12.  }
Важный момент: колличество потоков тут равно колличеству строк в файле proxies. Потому проксей нужно давать скрипту в пределах разумного :)

Далее идет процесс проверки проксей на валидность.
  1.  do {
  2.   while (($execrun = curl_multi_exec ($mc, $running)) == CURLM_CALL_MULTI_PERFORM);
  3.   if ($execrun != CURLM_OK) break;
  4.   while ($done = curl_multi_info_read ($mc))
  5.   {
  6.    $info = curl_getinfo ($done ['handle']);
  7.    if ($info ['http_code'] == 301) {
  8.     echo trim ($proxies [array_search ($done['handle'], $c)])."\r\n";
  9.    }
  10.    curl_multi_remove_handle ($mc, $done ['handle']);
  11.   }
  12.  } while ($running);
  13.  curl_multi_close ($mc);
Мой метод проверки отличается от других, я делаю это просто: устанавливаю проксик и скачиваю страничку Гоши (см. CURLOPT_URL, "http://google.com" код выше).

В полученом заголовке странички стоит редирект через header, потому что адрес http://google.com не используется а Гоша перебрасывает всех на www.google.com.

Чтобы получить код http header 301 использую функцию $info = curl_getinfo ($done ['handle']); ну и дальше уже делаю проверку кода и вывод результатов if ($info ['http_code'] == 301) { echo trim ($proxies [array_search ($done['handle'], $c)])."\r\n"; }

Проанализировав подобные конструкции я понял что у большинства программистов проблемы возникают в реализации параллельных запросов а именно в обработке рузультатов.

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

Так что пользуйтесь на здоровье.

Скачать сорец прокси чекера можно по ссылке [PHP прокси чекер (curl_multi)]

1 коммент.:

Max Lipsky комментирует...

Отличная статья, спасибо! :)

Отправить комментарий