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

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

Поэтому мой вопрос:

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

Вы можете получить расширение для 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.

Загрузите 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.ini, чтобы включить его. Найдите, где говорится что-то вроде

 ;;;;;;;;;;;;;;;;;;;;;; ; 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("\0")', 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("\0")', 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 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("\0")', 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; } } 

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

  • Не использует регулярные выражения
  • Правильно обрабатывает дубликаты заголовков
  • Не так много вызовов мутации массива и строки
  • Проводит строку состояния

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

 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; }