PHP - Различия между `get_headers` и`stream_get_meta_data`?

Вступление / Отказ от ответственности

Достойные куски этого являются результатами, которые можно в значительной степени игнорировать. Это все еще немного читатель, но я пытаюсь быть тщательным в своем анализе и опросе. Если вы знакомы с stream_get_meta_data , вы бы хорошо, чтобы перейти к "Вопросы" в конце.

Помимо документов, у меня возникают проблемы с поиском информации о PHP. stream_get_meta_data, Общая функциональность не сильно отличается от PHP get_headers, но я не могу на всю жизнь найти какие-либо сравнения между двумя, или плюсы / минусы первого.

Настройка

До этого момента я всегда использовал PHP get_headers проверить правильность URL. Недостаток с get_headers является то, что это общеизвестно медленно. Понятно, что большая часть задержки напрямую связана с сервером, на котором размещен интересующий сайт, но, возможно, метод просто чрезмерно устойчив, или что-то еще замедляет его.

Есть много ссылок, которые рекомендуют использовать CURL утверждая, что это быстрее, но я запустил параллельные, синхронизированные тесты обоих, и get_headers всегда выходил на первое место, часто в 1,5 или 2 раза.

Я еще не видел каких-либо решений, использующих stream_get_meta_data и только сегодня наткнулся на него впервые. Я исчерпал свои навыки Google, без особой удачи. Но в целях оптимизации моей схемы я провел несколько тестов.

Тестирование

Сравнения между get_headers а также stream_get_meta_data были запущены с использованием списка из 106 текущих (т. е. живых, действительных, status=200) URL:

Code Block #1

// All URLs in format "http://www.domain.com"
$urls = array('...', '...', '...'); // *106 URLs

// get_headers
$start = microtime(true);
foreach($urls as $url) {
    try{
        // Unfortunately, get_headers does not offer a context argument
        stream_context_set_default(array('http' => array('method' => "HEAD")));
        $headers[] = @get_headers($url, 1); 
        stream_context_set_default(array('http' => array('method' => "GET")));

    }catch(Exception $e){
        continue;
    }
}
$end1 = microtime(true) - $start;

// stream_get_meta_data
$cont = stream_context_create(array('http' => array('method' => "HEAD")));
$start = microtime(true);
foreach($urls as $url) {
    try{
        $fp = fopen($url, 'rb', false, $cont);
        if(!$fp) {
            continue;
        }
        $streams[] = stream_get_meta_data($fp);

    }catch(Exception $e){
        continue;
    }
}
$end2 = microtime(true) - $start;

И результаты, которые я получаю, stream_get_meta_data выходит на первое место, 90% времени или больше. Иногда времена почти идентичны, но чаще всего stream_get_meta_data имеет более короткое время выполнения

Run Times #1

"get_headers": 112.23 // seconds
"stream_get":  42.61 // seconds

С [stringified] выходами этих двух что-то вроде:

Excerpt of Comparison #1

url  ..  "http://www.wired.com/"

get_headers
|    0  ............................  "HTTP/1.1 200 OK"
|    Access-Control-Allow-Origin  ..  "*"
|    Cache-Control  ................  "stale-while-revalidate=86400, stale-while-error=86400"
|    Content-Type  .................  "text/html; charset=UTF-8"
|    Link  .........................  "; rel=\"https://api.w.org/\""
|    Server  .......................  "Apache"
|    Via
|    |    "1.1 varnish"
|    |    "1.1 varnish"
|    
|    Fastly-Debug-State  ...........  "HIT"
|    Fastly-Debug-Digest  ..........  "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
|    Content-Length  ...............  "135495"
|    Accept-Ranges  ................  "bytes"
|    Date  .........................  "Tue, 23 Aug 2016 22:32:26 GMT"
|    Age  ..........................  "701"
|    Connection  ...................  "close"
|    X-Served-By  ..................  "cache-jfk8149-JFK, cache-den6024-DEN"
|    X-Cache  ......................  "HIT, HIT"
|    X-Cache-Hits  .................  "51, 1"
|    X-Timer  ......................  "S1471991546.459931,VS0,VE0"
|    Vary  .........................  "Accept-Encoding"

stream_get
|    wrapper_data
|    |    "HTTP/1.1 200 OK"
|    |    "Access-Control-Allow-Origin: *"
|    |    "Cache-Control: stale-while-revalidate=86400, stale-while-error=86400"
|    |    "Content-Type: text/html; charset=UTF-8"
|    |    "Link: ; rel=\"https://api.w.org/\""
|    |    "Server: Apache"
|    |    "Via: 1.1 varnish"
|    |    "Fastly-Debug-State: HIT"
|    |    "Fastly-Debug-Digest: c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
|    |    "Content-Length: 135495"
|    |    "Accept-Ranges: bytes"
|    |    "Date: Tue, 23 Aug 2016 22:32:26 GMT"
|    |    "Via: 1.1 varnish"
|    |    "Age: 701"
|    |    "Connection: close"
|    |    "X-Served-By: cache-jfk8149-JFK, cache-den6020-DEN"
|    |    "X-Cache: HIT, HIT"
|    |    "X-Cache-Hits: 51, 1"
|    |    "X-Timer: S1471991546.614958,VS0,VE0"
|    |    "Vary: Accept-Encoding"
|    
|    wrapper_type  .................  "http"
|    stream_type  ..................  "tcp_socket/ssl"
|    mode  .........................  "rb"
|    unread_bytes  .................  0
|    seekable  .....................  false
|    uri  ..........................  "http://www.wired.com/"
|    timed_out  ....................  false
|    blocked  ......................  true
|    eof  ..........................  false

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

Достаточно просто...

Code Block #2.1/2.2

$wd = $meta[$url]['wrapper_data'];
$wArr = wrapperToKeys($wd);

где...

function wrapperToKeys($wd) {
    $wArr = array();
    foreach($wd as $row) {
        $pos = strpos($row, ': '); // *Assuming* that all separated by ": " (Might be colon, without the space?)

        if($pos === false) {
            $wArr[] = $row;
        }else {
            // $pos, $key and $value can probably be done with one good preg_match
            $key = substr($row, 0, $pos);
            $value = substr($row, ($pos + 2));

            // If key doesn't exist, assign value
            if(empty($wArr[$key])) {            
                $wArr[$key] = $value;
            }

            // If key already points to an array, add value to array
            else if(is_array($wArr[$key])) {    
                $wArr[$key][] = $value;
            }

            // If key currently points to string, swap value into an array
            else {                          
                $wArr[$key] = array($wArr[$key], $value);
            }
        }
    }

    return $wArr;
}

И вывод идентичен get_headers($url, 1):

Excerpt of Comparison #2

url  ..  "http://www.wired.com/"

headers
|    0  ............................  "HTTP/1.1 200 OK"
|    Access-Control-Allow-Origin  ..  "*"
|    Cache-Control  ................  "stale-while-revalidate=86400, stale-while-error=86400"
|    Content-Type  .................  "text/html; charset=UTF-8"
|    Link  .........................  "; rel=\"https://api.w.org/\""
|    Server  .......................  "Apache"
|    Via
|    |    "1.1 varnish"
|    |    "1.1 varnish"
|    
|    Fastly-Debug-State  ...........  "HIT"
|    Fastly-Debug-Digest  ..........  "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
|    Content-Length  ...............  "135495"
|    Accept-Ranges  ................  "bytes"
|    Date  .........................  "Tue, 23 Aug 2016 22:35:29 GMT"
|    Age  ..........................  "883"
|    Connection  ...................  "close"
|    X-Served-By  ..................  "cache-jfk8149-JFK, cache-den6027-DEN"
|    X-Cache  ......................  "HIT, HIT"
|    X-Cache-Hits  .................  "51, 1"
|    X-Timer  ......................  "S1471991729.021214,VS0,VE0"
|    Vary  .........................  "Accept-Encoding"

w-arr
|    0  ............................  "HTTP/1.1 200 OK"
|    Access-Control-Allow-Origin  ..  "*"
|    Cache-Control  ................  "stale-while-revalidate=86400, stale-while-error=86400"
|    Content-Type  .................  "text/html; charset=UTF-8"
|    Link  .........................  "; rel=\"https://api.w.org/\""
|    Server  .......................  "Apache"
|    Via
|    |    "1.1 varnish"
|    |    "1.1 varnish"
|    
|    Fastly-Debug-State  ...........  "HIT"
|    Fastly-Debug-Digest  ..........  "c245efbf14778c681ce317da114c1a762199e1326323d07b531d765e97fc8695"
|    Content-Length  ...............  "135495"
|    Accept-Ranges  ................  "bytes"
|    Date  .........................  "Tue, 23 Aug 2016 22:35:29 GMT"
|    Age  ..........................  "884"
|    Connection  ...................  "close"
|    X-Served-By  ..................  "cache-jfk8149-JFK, cache-den6021-DEN"
|    X-Cache  ......................  "HIT, HIT"
|    X-Cache-Hits  .................  "51, 1"
|    X-Timer  ......................  "S1471991729.173641,VS0,VE0"
|    Vary  .........................  "Accept-Encoding"

Даже с разбором ключей, stream_get_meta_data чемпион

Sample Run Times #2

"get_headers": 99.51 // seconds
"stream_get": 43.79 // seconds

Примечание. Эти тесты выполняются на дешевом общем сервере - отсюда и большие различия во времени тестирования. Тем не менее, разрыв между этими двумя методами очень согласован между тестами.

дополнительный

Для тех из вас, кто понимает c-код для PHP и чувствует, что может получить от него некоторое представление, определения функций можно найти по адресу:

'get_headers' (PHP Git)

а также

'stream_get_meta_data' (PHP Git)

Вопросы

  1. Как так stream_get_meta_data настолько недопредставлен (в поисках и доступных фрагментах кода) по сравнению с get_headers?

    То, как я это сформулировал, приводит к мнениям, но мое намерение больше похоже на: "Есть ли что-то настолько известное и ужасное в stream_get_meta_data что удерживает людей от его использования?

  2. Подобно предыдущему, существуют ли хорошо известные отраслевые согласованные плюсы и минусы между ними? Виды вещей, на которые намекает более полное понимание CS. возможно get_headers является более безопасным / надежным и менее восприимчивым к ошибкам и несоответствиям с выходными данными сервера? Или, может быть get_headers Известно, что работает в тех случаях, когда stream_get_meta_data выдает и ошибка?

    Из того, что я могу найти, stream_get_meta_data действительно есть пара замечаний и предупреждений (... для fopen), но ничего настолько ужасного, что их нельзя обойти.

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

Правка № 1

С тех пор я нашел несколько URL, которые успешно с get_headers но бросить предупреждение для stream_get_meta_data

PHP Warning:  fopen(http://www.alealimay.com/): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

PHP Warning:  fopen(http://www.thelovelist.net/): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

PHP Warning:  fopen(http://www.bleedingcool.com/): failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden

get_headers возвращает только 403 Forbidden статус, даже если вы можете вставить URL-адреса в браузер и увидеть, что они рабочие сайты.

Не уверены в этом: как разбивка stream_get_meta_data и неполный заголовок из get_headers (должен включать все перенаправления и окончательный status_code = 200 для функционирующих сайтов).


Большое спасибо, если вы сделали это так далеко.

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

0 ответов

Другие вопросы по тегам