X

Headers: Curl vs get_headers vs fsockopen

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

Из известных мне способов, есть три с помощью которых можно это сделать на php: curl, get_headers, и fsockopen. Я решил написать мини скрипт и протестировать все три способа. Тем более кодить ничего не пришлось, весь нужный функционал уже описан в комментах на php.net. Итак, у меня получилась такая програмка:

<?php

set_time_limit(300);
ob_implicit_flush(true);

function get_headers_curl($url)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL,            $url);
    curl_setopt($ch, CURLOPT_HEADER,         true);
    curl_setopt($ch, CURLOPT_NOBODY,         true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT,        15);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

    $r = curl_exec($ch);
    $r = explode("\n", $r);
    return $r;
}

function get_http_response_code($theURL) {
    $ret = @get_headers($theURL);
    return $ret;
}

 function get_headers_socket($Url, $Format= 0, $Depth= 0) {
    if ($Depth > 5) return;
    $Parts = parse_url($Url);
    if (!array_key_exists('path', $Parts))   $Parts['path'] = '/';
    if (!array_key_exists('port', $Parts))   $Parts['port'] = 80;
    if (!array_key_exists('scheme', $Parts)) $Parts['scheme'] = 'http';

    $Return = array();
    $fp = @fsockopen($Parts['host'], $Parts['port'], $errno, $errstr, 30);
    if ($fp) {
        $Out = 'GET '.$Parts['path'].(isset($Parts['query']) ? '?'.@$Parts['query'] : '')." HTTP/1.1\r\n".
               'Host: '.$Parts['host'].($Parts['port'] != 80 ? ':'.$Parts['port'] : '')."\r\n".
               'Connection: Close'."\r\n";
        fwrite($fp, $Out."\r\n");
        $Redirect = false; $RedirectUrl = '';
        while (!feof($fp) && $InLine = fgets($fp, 1280)) {
            if ($InLine == "\r\n") break;
            $InLine = rtrim($InLine);

            list($Key, $Value) = explode(': ', $InLine, 2);
            if ($Key == $InLine) {
                if ($Format == 1)
                        $Return[$Depth] = $InLine;
                else    $Return[] = $InLine;

                if (strpos($InLine, 'Moved') > 0) $Redirect = true;
            } else {
                if ($Key == 'Location') $RedirectUrl = $Value;
                if ($Format == 1)
                        $Return[$Key] = $Value;
                else    $Return[] = $Key.': '.$Value;
            }
        }
        fclose($fp);
        if ($Redirect && !empty($RedirectUrl)) {
            $NewParts = parse_url($RedirectUrl);
            if (!array_key_exists('host', $NewParts))   $RedirectUrl = $Parts['host'].$RedirectUrl;
            if (!array_key_exists('scheme', $NewParts)) $RedirectUrl = $Parts['scheme'].'://'.$RedirectUrl;
            $RedirectHeaders = get_headers_socket($RedirectUrl, $Format, $Depth+1);
            if ($RedirectHeaders) $Return = array_merge_recursive($Return, $RedirectHeaders);
        }
        return $Return;
    }
    return false;
}

$urls = array(
  'http://www.kleentek123456789.com/pdfs/OilManagement.pdf',
  'http://www.kleentek.com/pdfs/OilManagement.pdf',
  'http://www.interoncorp.com/pdfs/996470.pdf',
  'http://www.ramflat.com/pdf/aerosolv.pdf',
  'http://www.fpl.com/rates/pdf/lowbillR.pdf',
  'http://www.ced.umn.edu/forms/directory1.pdf',
  'http://www.strazishar.com/bulletin/page09.pdf',
  'http://bobdaubney.com/image2/THESTATEOFBOWLING.pdf',
  'http://www.4strokes.com/tech/exh_tune.pdf',
  'http://www.hatfieldmetal.com/hmfbrochure.pdf',
  'https://www.loveandlogic.com/Media/classroom.pdf',
  'http://www.hchsa.net/Newsletters/News08Fall.pdf',
  'http://www.fedstarcu.com/pdf/newsletter.pdf',
  'https://www.jscfcu.org/docs/membership-star.pdf',
  'http://www.ok.gov/~osbd/Closed/closcred.pdf',
  'http://www.stepforwardmichigan.org/rfv-72.aspx',
  'http://www.unitedccu.com/pdf/10_Annual_Report.pdf',
  'http://www.lasc.org/opinions/92ka2639.opn.pdf',
  'http://lake-viewcemetery.com/burials/wa_z.pdf',
  'http://www.forsythnchistory.com/files/whitaker.pdf',
  'http://www.ajlambert.com/cemetery/cmty_clc2.pdf',
  'http://www.bvarc.org/Tech/amplifiers.pdf',
  'http://www.minikits.com.au/doc/MMICSc.pdf',
);

echo '<body style="font-family:Tahoma; font-size:11px;">';

$work_time_res = array();

echo '<h3>CURL</h3>';
echo '<div style="height:200px;overflow:auto; border:1px solid silver;padding:10px;margin-bottom:5px;">';
$start_time = time();
foreach ($urls as $url)
{
    $answer =  get_headers_curl($url);
    if ($answer) $answer = implode("\n",$answer);
    echo date('H:i:s').' - '.$url.'<br>ANSWER: '.$answer.'<br><br>';
}

$work_time_res['CURL'] = time()-$start_time;
echo '</div>';
echo 'Work time: '.$work_time_res['CURL'].'sec<br>';

echo '<hr>';

echo '<h3>GET_HEADERS</h3>';
echo '<div style="height:200px;overflow:auto; border:1px solid silver;padding:10px;margin-bottom:5px;">';
$start_time = time();
foreach ($urls as $url)
{
    $answer =  @get_http_response_code($url);
    if ($answer) $answer = implode("\n",$answer);
    echo date('H:i:s').' - '.$url.'<br>ANSWER: '.$answer.'<br><br>';
}
$work_time_res['GET_HEADERS'] = time()-$start_time;
echo '</div>';
echo 'Work time: '.$work_time_res['GET_HEADERS'].'sec<br>';

echo '<hr>';

echo '<h3>GET_HEADERS_SOCKET</h3>';
echo '<div style="height:200px;overflow:auto; border:1px solid silver;padding:10px;margin-bottom:5px;">';
$start_time = time();
foreach ($urls as $url)
{
    $answer =  get_headers_socket($url);
    if ($answer) $answer = implode("\n",$answer);
    echo date('H:i:s').' - '.$url.'<br>ANSWER: '.$answer.'<br><br>';
}
$work_time_res['GET_HEADERS_SOCKET'] = time()-$start_time;
echo '</div>';
echo 'Work time: '.$work_time_res['GET_HEADERS_SOCKET'].'sec<br>';

echo '<hr>';

echo '<h3>WORK TIME</h3>';
foreach($work_time_res as $func=>$time) echo $func.' = '.count($urls).' urls in '.$time.' sec<br>';

echo '</body>';

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

Результаты получились вот такие:

CURL = 23 urls in 9 sec
GET_HEADERS = 23 urls in 11 sec
GET_HEADERS_SOCKET = 23 urls in 10 sec

Вот так выглядит лог работы:

Тестирование функций получения заголовков

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

Категории: PHP