Как получить функциональность заголовков HTTP parse без PECL?

Я использую PHP 5.3.5 в windows, и я не нашел никаких pecl_http.dll это работает с моей установкой.

Итак, мой вопрос:

Как получить функциональность http_parse_headers без использования PECL?

8 ответов


вы можете получить расширение для Windows на

это один из самых php_http-5.3-*-x86.zip файлы. Проверьте, какой PHP вы установили и выберите правильный, например, мой PHP-это php-5.3.6 -nts-Win32-VC9-x86, поэтому мне нужен php_http-5.3 -nts-svn20091125-vc9 - x86.застежка-молния.

загрузите zip и извлеките php_http.DLL в папку расширения. Папка расширения должна быть папка /ext в каталоге установки php. Если вы не уверены, откройте php.ini-файл и поиск этих строк:

; Directory in which the loadable extensions (modules) reside.
; http://php.net/extension-dir
; extension_dir = "./"
; On windows:
extension_dir = .\ext

значение extension_dir-это то, где вы должны разместить dll. Если вы не уверены, где ваш PHP.ini находится, откройте командную строку и выполните

php --ini

это скажет вам, где ваш PHP.ini-это. Он выведет что-то вроде

Configuration File (php.ini) Path: C:\Windows
Loaded Configuration File:         C:\php5\php-5.3.6-nts-Win32-VC9-x86\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

после того, как вы скопировали dll, добавьте расширение в свой php.Ини включить его. Найти, где он говорит что-то вроде

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

там должно быть несколько строк следующего вида:

;extension=php_sybase_ct.dll
extension=php_tidy.dll
;extension=php_xmlrpc.dll
extension=php_xsl.dll
;extension=php_zip.dll

добавить следующую строку:

extension=php_http.dll

сохранить php.ini и введите в командной строке следующее:

php --ri http

теперь вы должны получить довольно обширный выход, начиная с

http
HTTP Support => enabled
Extension Version => 1.7.0-dev
… more stuff

это означает, что вы успешно установили расширение и можете использовать его сейчас.

обратите внимание, что в порядке чтобы иметь возможность загружать это расширение в Windows, вам дополнительно нужно загрузить следующие расширения PHP: hash, iconv и SPL.


на странице документации, первый комментарий:

 if( !function_exists( 'http_parse_headers' ) ) {
     function http_parse_headers( $header )
     {
         $retVal = array();
         $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
         foreach( $fields as $field ) {
             if( preg_match('/([^:]+): (.+)/m', $field, $match) ) {
                 $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("")', strtolower(trim($match[1])));
                 if( isset($retVal[$match[1]]) ) {
                     $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
                 } else {
                     $retVal[$match[1]] = trim($match[2]);
                 }
             }
         }
         return $retVal;
     }
}

кроме того, вы можете прочитать, как установить расширение PECL на Windows, если честно, я ничего об этом не знаю.


Это также снято с PHP документация для http_parse_headers. Когда я сравнивал его с @Berry Langerakответ (используя microtime) Я обнаружил, что он в среднем на 17% быстрее, используя образец из 10 заголовков (предположительно, потому что он не использует регулярные выражения).

if (!function_exists('http_parse_headers')) {
    function http_parse_headers($raw_headers) {
        $headers = array();
        $key = '';

        foreach(explode("\n", $raw_headers) as $i => $h) {
            $h = explode(':', $h, 2);

            if (isset($h[1])) {
                if (!isset($headers[$h[0]]))
                    $headers[$h[0]] = trim($h[1]);
                elseif (is_array($headers[$h[0]])) {
                    $headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1])));
                }
                else {
                    $headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1])));
                }

                $key = $h[0];
            }
            else { 
                if (substr($h[0], 0, 1) == "\t")
                    $headers[$key] .= "\r\n\t".trim($h[0]);
                elseif (!$key) 
                    $headers[0] = trim($h[0]); 
            }
        }

        return $headers;
    }
}

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


регулярное выражение Функция

0.00035881996
0.00036096572
0.00034999847
0.00043797492
0.00033497810

средний: 0.000368547434

Эта Функция

0.00006198883
0.00006604194
0.00007104873
0.00006413459
0.00006389617

среднее 0,000065422052


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

function dirtyHeaderParser($headers, $strict = true){
    $arr = array();
    $s = strtok($headers, ':');
    while ($s){
        if ( ($s[0] === ' ') || ($s[0] === "\t") ){
            if (count($arr) != 0){
                $tail = strtok('');
                $tail = "{$s}:{$tail}";
                $v = strtok($tail, "\n");
                if (is_array($arr[$key])){
                    end($arr[$key]);
                    $last = key($arr[$key]);
                    $arr[$key][$last] = "{$arr[$key][$last]}\n{$v}";
                    reset($arr[$key]);
                } else {
                    $arr[$key] = "{$arr[$key]}\n{$v}";
                }
            }
        } else {
            $v = strtok("\n");
            if ($v){
                $key = strtolower($s);
                if (((strpos($key, "\n") !== false) || (strpos($key, "\t") !== false) || (strpos($key, " ") !== false)) && $strict) {
                    return false;
                } 
                if (array_key_exists($key, $arr)){
                    if (!is_array($arr[$key])){
                        $arr[$key] = array($arr[$key]);
                    }
                    $arr[$key][] = trim($v);
                } else {
                    $arr[$key] = trim($v);
                }
            } else {
                break;
            }
        }
        $s = strtok(':');
    }
    return (count($arr) == 0) ? false : $arr;
}

строгий режим означает, что он вернется false если ключ заголовка содержит \n, пробел или \t. Он поддерживает несколько заголовков строк и двойные значения заголовков (с несколькими строками тоже), если кто-то найдет что-то не похожее на версию PECL, я был бы рад, если вы оставите комментарий.


вот измененная версия формы страницы документации, которая работает так же, как версия PECL :)

function http_parse_headers( $header ) {
        $retVal = array();
        $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
        foreach( $fields as $field ) {
            if( preg_match('/([^:]+): (.+)/m', $field, $match) ) {
                $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("")', strtolower(trim($match[1])));
                if( isset($retVal[$match[1]]) ) {
                    if ( is_array( $retVal[$match[1]] ) ) {
                        $i = count($retVal[$match[1]]);
                        $retVal[$match[1]][$i] = $match[2];
                    }
                    else {
                        $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
                    }
                } else {
                    $retVal[$match[1]] = trim($match[2]);
                }
            }
        }
        return $retVal;
    }

ненавижу продолжать такой старый поток, который уже так долго, но этот превосходит, потому что:

  • не использует регулярные выражения
  • обрабатывает повторяющиеся заголовки правильно
  • не так много вызовов мутаций массива и строки
  • анализирует строку состояния

(возможно, Вам понадобится код, чтобы проверить, существует ли расширение)

function http_parse_headers ($raw) {
    $res = [];
    foreach (explode("\n", $raw) as $h) {
        $h = explode(':', $h, 2);
        $first = trim($h[0]);
        $last = trim($h[1]);
        if (array_key_exists($first, $res)) {
            $res[$first] .= ", " . $last;
        } else if (isset($h[1])) {
            $res[$first] = $last;
        } else {
            $res[] = $first;
        }
    }
    return $res;
}

function parse_headers($headers)
{
    $headers = preg_replace('/^\r\n/m', '', $headers);
    $headers = preg_replace('/\r\n\s+/m', ' ', $headers);
    preg_match_all('/^([^: ]+):\s(.+?(?:\r\n\s(?:.+?))*)?\r\n/m', $headers . "\r\n", $matches);

    $result = array();
    foreach ($matches[1] as $key => $value)
        $result[$value] = (array_key_exists($value, $result) ? $result[$value] . "\n" : '') . $matches[2][$key];

    return $result;
}

к сожалению, для функции, представленной на странице документации, если существует более двух одинаковых заголовков (т. е. Set-Cookie), структура массива будет неправильной, например:

    [Set-Cookie] => Array
    (
        [0] => Array
        (
            [0] => AWESOMESESSIONID=xQ5TRl1GXDQcQCXytfb1PK!-744872953!NONE; Path=/cte-lps2s-test2/; Secure
            [1] => AWESOME_SESSH_c25c28d0-b763-11df-979f23a029aa77=%2Fcte-lps2s-test2; Path=/
        ) 
        [1] => MOREAWESOME=2_uGgNpo2-jm-CjfaefLzjFhmmP-y3HzwNZKE0gsTeP+; Path=/; Secure
    )

приведенная ниже модификация кода исправит эту ошибку (см. комментарий):

if( !function_exists( 'http_parse_headers' ) ) {
     function http_parse_headers( $header )
     {
         $retVal = array();
         $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ',$header));
         foreach( $fields as $field ) {
             if( preg_match('/([^:]+): (.+)/m', $field, $match) ) {
                 $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("")',     strtolower(trim($match[1])));
                 // We need to check if an array of values has already been created, to     maintain the correct level in the $retVal array.
                 if(is_array($retVal[$match[1]])) {
                        $retVal[$match[1]] []= $match[2];
                 }
                 else {
                    $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
                 }
             } else {
                 $retVal[$match[1]] = trim($match[2]);
             }
         }
         return $retVal;
     }
}