├── .gitignore ├── .travis.yml ├── HTTP2.php ├── HTTP2 └── Exception.php ├── LICENSE ├── README.rst ├── composer.json ├── phpunit.xml └── tests ├── absoluteURI.inc ├── negotiateCharset.phpt ├── negotiateCharset2.phpt ├── negotiateLanguage.phpt ├── negotiateMimeType.phpt ├── parseLinks_array.phpt ├── parseLinks_multiple.phpt ├── parseLinks_real.phpt ├── parseLinks_rel-no-quote.phpt ├── parseLinks_rfc5988-examples-1.phpt ├── parseLinks_rfc5988-examples-2.phpt ├── parseLinks_rfc5988-examples-3.phpt ├── parseLinks_rfc5988-examples-4.phpt ├── test1a.phpt ├── test2a.phpt ├── test3a.phpt ├── test4a.phpt ├── test5a.phpt └── test6a.phpt /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /releases/ 3 | /.phpunit.result.cache 4 | 5 | # composer related 6 | composer.lock 7 | composer.phar 8 | vendor 9 | /dist/ 10 | /README.htm 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 7.4 4 | - 8.0 5 | - 8.1 6 | - 8.2 7 | install: 8 | - composer install 9 | script: 10 | - ./vendor/bin/phpunit 11 | -------------------------------------------------------------------------------- /HTTP2.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Sterling Hughes 11 | * @author Tomas V.V.Cox 12 | * @author Richard Heyes 13 | * @author Philippe Jausions 14 | * @author Michael Wallner 15 | * @copyright 2002-2008 The Authors 16 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 17 | * @link http://pear.php.net/package/HTTP2 18 | */ 19 | 20 | /** 21 | * Miscellaneous HTTP Utilities 22 | * 23 | * PEAR::HTTP2 provides shorthand methods for generating HTTP dates, 24 | * issueing HTTP HEAD requests, building absolute URIs, firing redirects and 25 | * negotiating user preferred language. 26 | * 27 | * @category HTTP 28 | * @package HTTP2 29 | * @author Stig Bakken 30 | * @author Sterling Hughes 31 | * @author Tomas V.V.Cox 32 | * @author Richard Heyes 33 | * @author Philippe Jausions 34 | * @author Michael Wallner 35 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 36 | * @version Release: @version@ 37 | * @link http://pear.php.net/package/HTTP2 38 | */ 39 | class HTTP2 40 | { 41 | /** 42 | * Formats a RFC compliant GMT date HTTP header. This function honors the 43 | * "y2k_compliance" php.ini directive and formats the GMT date corresponding 44 | * to either RFC850 or RFC822. 45 | * 46 | * @param mixed $time unix timestamp or date (default = current time) 47 | * 48 | * @return string|boolean GMT date string, or FALSE for an invalid 49 | * $time parameter 50 | */ 51 | public function date($time = null) 52 | { 53 | if (!isset($time)) { 54 | $time = time(); 55 | } elseif (!is_numeric($time) && (-1 === $time = strtotime($time))) { 56 | return false; 57 | } 58 | 59 | // RFC822 or RFC850 60 | $format = ini_get('y2k_compliance') ? 'D, d M Y' : 'l, d-M-y'; 61 | 62 | return gmdate($format .' H:i:s \G\M\T', $time); 63 | } 64 | 65 | /** 66 | * Negotiates language with the user's browser through the Accept-Language 67 | * HTTP header or the user's host address. Language codes are generally in 68 | * the form "ll" for a language spoken in only one country, or "ll-CC" for a 69 | * language spoken in a particular country. For example, U.S. English is 70 | * "en-US", while British English is "en-UK". Portugese as spoken in 71 | * Portugal is "pt-PT", while Brazilian Portugese is "pt-BR". 72 | * 73 | * Quality factors in the Accept-Language: header are supported, e.g.: 74 | * Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8 75 | * 76 | * 77 | * require_once 'HTTP2.php'; 78 | * $http = new HTTP2(); 79 | * $langs = array( 80 | * 'en' => 'locales/en', 81 | * 'en-US' => 'locales/en', 82 | * 'en-UK' => 'locales/en', 83 | * 'de' => 'locales/de', 84 | * 'de-DE' => 'locales/de', 85 | * 'de-AT' => 'locales/de', 86 | * ); 87 | * $neg = $http->negotiateLanguage($langs); 88 | * $dir = $langs[$neg]; 89 | * 90 | * 91 | * @param array $supported An associative array of supported languages, 92 | * whose values must evaluate to true. 93 | * @param string $default The default language to use if none is found. 94 | * 95 | * @return string The negotiated language result or the supplied default. 96 | */ 97 | public function negotiateLanguage($supported, $default = 'en-US') 98 | { 99 | $supp = array(); 100 | foreach ($supported as $lang => $isSupported) { 101 | if ($isSupported) { 102 | $supp[strtolower($lang)] = $lang; 103 | } 104 | } 105 | 106 | if (!count($supp)) { 107 | return $default; 108 | } 109 | 110 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { 111 | $match = $this->matchAccept( 112 | $_SERVER['HTTP_ACCEPT_LANGUAGE'], 113 | $supp 114 | ); 115 | if (!is_null($match)) { 116 | return $match; 117 | } 118 | } 119 | 120 | if (isset($_SERVER['REMOTE_HOST'])) { 121 | $lang = strtolower(end($h = explode('.', $_SERVER['REMOTE_HOST']))); 122 | if (isset($supp[$lang])) { 123 | return $supp[$lang]; 124 | } 125 | } 126 | 127 | return $default; 128 | } 129 | 130 | /** 131 | * Negotiates charset with the user's browser through the Accept-Charset 132 | * HTTP header. 133 | * 134 | * Quality factors in the Accept-Charset: header are supported, e.g.: 135 | * Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8 136 | * 137 | * 138 | * require_once 'HTTP2.php'; 139 | * $http = new HTTP2(); 140 | * $charsets = array( 141 | * 'UTF-8', 142 | * 'ISO-8859-1', 143 | * ); 144 | * $charset = $http->negotiateCharset($charsets); 145 | * 146 | * 147 | * @param array $supported An array of supported charsets 148 | * @param string $default The default charset to use if none is found. 149 | * 150 | * @return string The negotiated language result or the supplied default. 151 | * @author Philippe Jausions 152 | */ 153 | public function negotiateCharset($supported, $default = 'ISO-8859-1') 154 | { 155 | $supp = array(); 156 | foreach ($supported as $charset) { 157 | $supp[strtolower($charset)] = $charset; 158 | } 159 | 160 | if (!count($supp)) { 161 | return $default; 162 | } 163 | 164 | if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) { 165 | $match = $this->matchAccept( 166 | $_SERVER['HTTP_ACCEPT_CHARSET'], 167 | $supp 168 | ); 169 | 170 | if (!is_null($match)) { 171 | return $match; 172 | } 173 | } 174 | 175 | return $default; 176 | } 177 | 178 | /** 179 | * Negotiates content type with the user's browser through the Accept 180 | * HTTP header. 181 | * 182 | * Quality factors in the Accept: header are supported, e.g.: 183 | * Accept: application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8 184 | * 185 | * 186 | * require_once 'HTTP2.php'; 187 | * $http = new HTTP2(); 188 | * $contentType = array( 189 | * 'application/xhtml+xml', 190 | * 'application/xml', 191 | * 'text/html', 192 | * 'text/plain', 193 | * ); 194 | * $mime = $http->negotiateMimeType($contentType); 195 | * 196 | * 197 | * @param array $supported An associative array of supported MIME types. 198 | * @param string $default The default type to use if none match. 199 | * 200 | * @return string The negotiated MIME type result or the supplied default. 201 | * @author Philippe Jausions 202 | */ 203 | public function negotiateMimeType($supported, $default) 204 | { 205 | $supp = array(); 206 | foreach ($supported as $type) { 207 | $supp[strtolower($type)] = $type; 208 | } 209 | 210 | if (!count($supp)) { 211 | return $default; 212 | } 213 | 214 | if (isset($_SERVER['HTTP_ACCEPT'])) { 215 | $accepts = $this->sortAccept($_SERVER['HTTP_ACCEPT']); 216 | 217 | foreach ($accepts as $type => $q) { 218 | if (substr($type, -2) != '/*') { 219 | if (isset($supp[$type])) { 220 | return $supp[$type]; 221 | } 222 | continue; 223 | } 224 | if ($type == '*/*') { 225 | return array_shift($supp); 226 | } 227 | list($general, $specific) = explode('/', $type); 228 | $general .= '/'; 229 | $len = strlen($general); 230 | foreach ($supp as $mime => $t) { 231 | if (strncasecmp($general, $mime, $len) == 0) { 232 | return $t; 233 | } 234 | } 235 | } 236 | } 237 | 238 | return $default; 239 | } 240 | 241 | /** 242 | * Parses a weighed "Accept" HTTP header and matches it against a list 243 | * of supported options 244 | * 245 | * @param string $header The HTTP "Accept" header to parse 246 | * @param array $supported A list of supported values 247 | * 248 | * @return string|NULL a matched option, or NULL if no match 249 | */ 250 | protected function matchAccept($header, $supported) 251 | { 252 | $matches = $this->sortAccept($header); 253 | foreach ($matches as $key => $q) { 254 | if (isset($supported[$key])) { 255 | return $supported[$key]; 256 | } 257 | } 258 | // If any (i.e. "*") is acceptable, return the first supported format 259 | if (isset($matches['*'])) { 260 | return array_shift($supported); 261 | } 262 | return null; 263 | } 264 | 265 | /** 266 | * Parses and sorts a weighed "Accept" HTTP header 267 | * 268 | * @param string $header The HTTP "Accept" header to parse 269 | * 270 | * @return array Sorted list of "accept" options 271 | */ 272 | protected function sortAccept($header) 273 | { 274 | $matches = array(); 275 | foreach (explode(',', $header) as $option) { 276 | $option = array_map('trim', explode(';', $option)); 277 | 278 | $l = strtolower($option[0]); 279 | if (isset($option[1])) { 280 | $q = (float) str_replace('q=', '', $option[1]); 281 | } else { 282 | $q = null; 283 | // Assign default low weight for generic values 284 | if ($l == '*/*') { 285 | $q = 0.01; 286 | } elseif (substr($l, -1) == '*') { 287 | $q = 0.02; 288 | } 289 | } 290 | // Unweighted values, get high weight by their position in the 291 | // list 292 | $matches[$l] = isset($q) ? $q : 1000 - count($matches); 293 | } 294 | arsort($matches, SORT_NUMERIC); 295 | return $matches; 296 | } 297 | 298 | /** 299 | * Sends a "HEAD" HTTP command to a server and returns the headers 300 | * as an associative array. 301 | * 302 | * Example output could be: 303 | * 304 | * Array 305 | * ( 306 | * [response_code] => 200 // The HTTP response code 307 | * [response] => HTTP/1.1 200 OK // The full HTTP response string 308 | * [Date] => Fri, 11 Jan 2002 01:41:44 GMT 309 | * [Server] => Apache/1.3.20 (Unix) PHP/4.1.1 310 | * [X-Powered-By] => PHP/4.1.1 311 | * [Connection] => close 312 | * [Content-Type] => text/html 313 | * ) 314 | * 315 | * 316 | * @param string $url A valid URL, e.g.: http://pear.php.net/credits.php 317 | * @param integer $timeout Timeout in seconds (default = 10) 318 | * 319 | * @return array Returns associative array of response headers on success 320 | * 321 | * @throws HTTP2_Exception When connecting fails 322 | * @throws InvalidArgumentException When the protocol is not uspported 323 | * 324 | * @see HTTP_Client::head() 325 | * @see HTTP_Request 326 | */ 327 | public function head($url, $timeout = 10) 328 | { 329 | $p = parse_url($url); 330 | if (!isset($p['scheme'])) { 331 | $p = parse_url($this->absoluteURI($url)); 332 | } elseif ($p['scheme'] != 'http') { 333 | throw new InvalidArgumentException( 334 | 'Unsupported protocol: '. $p['scheme'] 335 | ); 336 | } 337 | 338 | $port = isset($p['port']) ? $p['port'] : 80; 339 | 340 | if (!$fp = @fsockopen($p['host'], $port, $eno, $estr, $timeout)) { 341 | throw new HTTP2_Exception("Connection error: $estr ($eno)"); 342 | } 343 | 344 | $path = !empty($p['path']) ? $p['path'] : '/'; 345 | $path .= !empty($p['query']) ? '?' . $p['query'] : ''; 346 | 347 | fputs($fp, "HEAD $path HTTP/1.0\r\n"); 348 | fputs($fp, 'Host: ' . $p['host'] . ':' . $port . "\r\n"); 349 | fputs($fp, "Connection: close\r\n\r\n"); 350 | 351 | $response = rtrim(fgets($fp, 4096)); 352 | if (preg_match("|^HTTP/[^\s]*\s(.*?)\s|", $response, $status)) { 353 | $headers['response_code'] = $status[1]; 354 | } 355 | $headers['response'] = $response; 356 | 357 | while ($line = fgets($fp, 4096)) { 358 | if (!trim($line)) { 359 | break; 360 | } 361 | if (($pos = strpos($line, ':')) !== false) { 362 | $header = substr($line, 0, $pos); 363 | $value = trim(substr($line, $pos + 1)); 364 | 365 | $headers[$header] = $value; 366 | } 367 | } 368 | fclose($fp); 369 | return $headers; 370 | } 371 | 372 | /** 373 | * This function redirects the client. This is done by issuing 374 | * a "Location" header and exiting if wanted. If you set $rfc2616 to true 375 | * HTTP will output a hypertext note with the location of the redirect. 376 | * 377 | * @param string $url URL where the redirect should go to. 378 | * @param bool $exit Whether to exit immediately after redirection. 379 | * @param bool $rfc2616 Wheter to output a hypertext note where we're 380 | * redirecting to (Redirecting to 381 | * ....) 382 | * 383 | * @return boolean Returns TRUE on succes (or exits) or FALSE if headers 384 | * have already been sent. 385 | */ 386 | function redirect($url, $exit = true, $rfc2616 = false) 387 | { 388 | if (headers_sent()) { 389 | return false; 390 | } 391 | 392 | $url = $this->absoluteURI($url); 393 | header('Location: '. $url); 394 | 395 | if ($rfc2616 && isset($_SERVER['REQUEST_METHOD']) 396 | && $_SERVER['REQUEST_METHOD'] != 'HEAD' 397 | ) { 398 | echo ' 399 |

Redirecting to: ' 400 | .htmlspecialchars($url).'.

401 | '; 409 | } 410 | if ($exit) { 411 | exit; 412 | } 413 | return true; 414 | } 415 | 416 | /** 417 | * This function returns the absolute URI for the partial URL passed. 418 | * The current scheme (HTTP/HTTPS), host server, port, current script 419 | * location are used if necessary to resolve any relative URLs. 420 | * 421 | * Offsets potentially created by PATH_INFO are taken care of to resolve 422 | * relative URLs to the current script. 423 | * 424 | * You can choose a new protocol while resolving the URI. This is 425 | * particularly useful when redirecting a web browser using relative URIs 426 | * and to switch from HTTP to HTTPS, or vice-versa, at the same time. 427 | * 428 | * @param string $url Absolute or relative URI the redirect should 429 | * go to. 430 | * @param string $protocol Protocol to use when redirecting URIs. 431 | * @param integer $port A new port number. 432 | * 433 | * @return string The absolute URI. 434 | * @author Philippe Jausions 435 | */ 436 | public function absoluteURI($url = null, $protocol = null, $port = null) 437 | { 438 | if ($url === null) { 439 | $url = ''; 440 | } 441 | // filter CR/LF 442 | $url = str_replace(array("\r", "\n"), ' ', $url); 443 | 444 | // Mess around protocol and port with already absolute URIs 445 | if (preg_match('!^([a-z0-9]+)://!i', $url)) { 446 | if (empty($protocol) && empty($port)) { 447 | return $url; 448 | } 449 | if (!empty($protocol)) { 450 | $url = $protocol .':'. end($array = explode(':', $url, 2)); 451 | } 452 | if (!empty($port)) { 453 | $url = preg_replace( 454 | '!^(([a-z0-9]+)://[^/:]+)(:[\d]+)?!i', 455 | '\1:'. $port, 456 | $url 457 | ); 458 | } 459 | return $url; 460 | } 461 | 462 | $host = 'localhost'; 463 | if (!empty($_SERVER['HTTP_HOST'])) { 464 | list($host) = explode(':', $_SERVER['HTTP_HOST']); 465 | } elseif (!empty($_SERVER['SERVER_NAME'])) { 466 | list($host) = explode(':', $_SERVER['SERVER_NAME']); 467 | } 468 | 469 | if (empty($protocol)) { 470 | if (isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'], 'on')) { 471 | $protocol = 'https'; 472 | } else { 473 | $protocol = 'http'; 474 | } 475 | if (!isset($port) || $port != intval($port)) { 476 | $port = 80; 477 | if (isset($_SERVER['SERVER_PORT'])) { 478 | $port = $_SERVER['SERVER_PORT']; 479 | } 480 | } 481 | } 482 | 483 | if ($protocol == 'http' && $port == 80) { 484 | unset($port); 485 | } 486 | if ($protocol == 'https' && $port == 443) { 487 | unset($port); 488 | } 489 | 490 | $server = $protocol.'://'.$host.(isset($port) ? ':'.$port : ''); 491 | 492 | $uriAll = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] 493 | : $_SERVER['PHP_SELF']; 494 | if (false !== ($q = strpos($uriAll, '?'))) { 495 | $uriBase = substr($uriAll, 0, $q); 496 | } else { 497 | $uriBase = $uriAll; 498 | } 499 | if (!strlen($url) || $url[0] == '#') { 500 | $url = $uriAll.$url; 501 | } elseif ($url[0] == '?') { 502 | $url = $uriBase.$url; 503 | } 504 | if ($url[0] == '/') { 505 | return $server . $url; 506 | } 507 | 508 | // Adjust for PATH_INFO if needed 509 | if (isset($_SERVER['PATH_INFO']) && strlen($_SERVER['PATH_INFO'])) { 510 | $path = dirname(substr($uriBase, 0, -strlen($_SERVER['PATH_INFO']))); 511 | } else { 512 | /** 513 | * Fixes bug #12672 PHP_SELF ending on / causes incorrect redirects 514 | * 515 | * @link http://pear.php.net/bugs/12672 516 | */ 517 | $path = dirname($uriBase.'-'); 518 | } 519 | 520 | if (substr($path = strtr($path, '\\', '/'), -1) != '/') { 521 | $path .= '/'; 522 | } 523 | 524 | return $server . $path . $url; 525 | } 526 | 527 | /** 528 | * Parses a HTTP "Link" header value as specified by RFC 5988. 529 | * 530 | * When errors occur during parsing, all information collected to that 531 | * point will be returned used and the rest of the line skipped. 532 | * 533 | * @param string|array $lines HTTP "Link:" header value (without "Link:"), 534 | * or array of such strings 535 | * 536 | * @return array Array of parsed links 537 | * (one single line may contain multiple links) 538 | * Only params existing in the link are in the array. 539 | * URI is available in key "_uri". 540 | * 541 | * @link http://tools.ietf.org/html/rfc5988 542 | */ 543 | public function parseLinks($lines) 544 | { 545 | $lines = (array) $lines; 546 | $extracted = array(); 547 | 548 | foreach ($lines as $line) { 549 | $state = 'uri'; 550 | $pos = 0; 551 | $len = strlen($line); 552 | while ($pos < $len - 1) { 553 | $link = array(); 554 | $pos = $len - strlen(ltrim(substr($line, $pos))); 555 | if ($line[$pos] == ',') { 556 | ++$pos; 557 | continue; 558 | } else if ($line[$pos] != '<') { 559 | break; 560 | } 561 | $end = strpos($line, '>', $pos + 1); 562 | if ($end === false) { 563 | break; 564 | } 565 | $link['_uri'] = substr($line, $pos + 1, $end - $pos - 1); 566 | $pos = $end + 1; 567 | 568 | while ($pos < $len - 1) { 569 | if ($line[$pos] == ',') { 570 | $extracted[] = $link; 571 | $link = array(); 572 | ++$pos; 573 | continue; 574 | } else if ($line[$pos] != ';') { 575 | break; 576 | } 577 | 578 | ++$pos; 579 | $end = strpos($line, '=', $pos + 1); 580 | if ($end === false) { 581 | break; 582 | } 583 | $pname = trim(substr($line, $pos, $end - $pos)); 584 | $pos = $end + 1; 585 | 586 | $rest = trim(substr($line, $pos)); 587 | if ($rest[0] == '"') { 588 | $pos = strpos($line, '"', $pos) + 1; 589 | $end = strpos($line, '"', $pos + 1); 590 | $pval = substr($line, $pos, $end - $pos); 591 | $pos = $end + 1; 592 | } else { 593 | $end1 = strpos($line, ';', $pos + 1); 594 | $end2 = strpos($line, ',', $pos + 1); 595 | if ($end1 === false && $end2 === false) { 596 | $end = $len; 597 | } else if ($end1 === false) { 598 | $end = $end2; 599 | } else if ($end2 === false) { 600 | $end = $end1; 601 | } else { 602 | $end = $end1 < $end2 ? $end1 : $end2; 603 | } 604 | $pval = trim(substr($line, $pos, $end - $pos)); 605 | $pos = $end; 606 | } 607 | if ($pname == 'title*') { 608 | $parts = explode("'", $pval, 3); 609 | if (count($parts) != 3) { 610 | continue; 611 | } 612 | list($charset, $lang, $val) = $parts; 613 | $link[$pname][$lang] = $this->convertCharset( 614 | $charset, 'utf-8', urldecode($val) 615 | ); 616 | } else if ($pname == 'rel' || $pname == 'rev') { 617 | if (!isset($link[$pname])) { 618 | $link[$pname] = array(); 619 | } 620 | $link[$pname] = array_merge( 621 | $link[$pname], 622 | array_map('trim', explode(' ', $pval)) 623 | ); 624 | } else if (!isset($link[$pname])) { 625 | $link[$pname] = $pval; 626 | } 627 | if ($end >= $len || $line[$end] == ',') { 628 | break; 629 | } 630 | } 631 | if (count($link) > 0) { 632 | $extracted[] = $link; 633 | } 634 | } 635 | } 636 | 637 | return $extracted; 638 | } 639 | 640 | /** 641 | * Convert the given string from one into another charset. 642 | * Uses mb_convert_encoding or iconv if available. 643 | * 644 | * @param string $from Source charset the string is in 645 | * @param string $to Target character set 646 | * @param string $str String to convert 647 | * 648 | * @return string converted string 649 | */ 650 | protected function convertCharset($from, $to, $str) 651 | { 652 | if (function_exists('mb_convert_encoding')) { 653 | return mb_convert_encoding($str, $to, $from); 654 | } else if (function_exists('iconv')) { 655 | return iconv($from, $to, $str); 656 | } 657 | return $str; 658 | } 659 | } 660 | ?> 661 | -------------------------------------------------------------------------------- /HTTP2/Exception.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2012-2013 The Authors 11 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 12 | * @link http://pear.php.net/package/HTTP2 13 | */ 14 | 15 | /** 16 | * Simple exception class for HTTP2 17 | * 18 | * @category HTTP 19 | * @package HTTP2 20 | * @author Daniel O'Connor 21 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 22 | * @version Release: @version@ 23 | * @link http://pear.php.net/package/HTTP2 24 | */ 25 | class HTTP2_Exception extends Exception 26 | { 27 | } 28 | ?> 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002-2005, 2 | Stig Bakken , 3 | Sterling Hughes , 4 | Tomas V.V.Cox , 5 | Richard Heyes , 6 | Philippe Jausions , 7 | Michael Wallner . 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | * Redistributions of source code must retain the above copyright notice, 14 | this list of conditions and the following disclaimer. 15 | * Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ************************************ 2 | HTTP2 - Miscellaneous HTTP utilities 3 | ************************************ 4 | Static methods for doing miscellaneous HTTP related stuff like 5 | date formatting, language negotiation or HTTP redirection. 6 | 7 | 8 | Features 9 | ======== 10 | - Language negotiation 11 | - MIME type negotiation 12 | - Charset negotiation 13 | - Send HEAD requests to URLs 14 | - Make URLs absolute 15 | - Parse HTTP ``Link:`` header values (RFC 5988) 16 | 17 | 18 | Installation 19 | ============ 20 | :: 21 | 22 | $ composer require pear/http2 23 | 24 | 25 | Usage 26 | ===== 27 | 28 | Language negotiation 29 | -------------------- 30 | Quality factors in the ``Accept-Language:`` header are supported, e.g.:: 31 | 32 | Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8 33 | 34 | Code:: 35 | 36 | 'locales/en', 40 | 'en-US' => 'locales/en', 41 | 'en-UK' => 'locales/en', 42 | 'de' => 'locales/de', 43 | 'de-DE' => 'locales/de', 44 | 'de-AT' => 'locales/de', 45 | ); 46 | $neg = $http->negotiateLanguage($langs); 47 | $dir = $langs[$neg]; 48 | ?> 49 | 50 | 51 | Charset negotiation 52 | ------------------- 53 | :: 54 | 55 | negotiateCharset($charsets); 62 | ?> 63 | 64 | 65 | MIME type negotiation 66 | --------------------- 67 | :: 68 | 69 | negotiateMimeType($contentType); 78 | ?> 79 | 80 | 81 | Links 82 | ===== 83 | Homepage 84 | http://pear.php.net/package/HTTP2 85 | Bug tracker 86 | http://pear.php.net/bugs/search.php?cmd=display&package_name[]=HTTP2 87 | Documentation 88 | http://pear.php.net/package/HTTP2/docs 89 | Unit test status 90 | https://travis-ci.org/pear/HTTP2 91 | 92 | .. image:: https://travis-ci.org/pear/HTTP2.svg?branch=master 93 | :target: https://travis-ci.org/pear/HTTP2 94 | Packagist 95 | https://packagist.org/packages/pear/http2 96 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pear/http2", 3 | "description": "Miscellaneous HTTP utilities", 4 | "type": "library", 5 | "authors": [ 6 | { 7 | "email": "mike@php.net", 8 | "name": "Michael Wallner", 9 | "role": "Lead" 10 | }, 11 | { 12 | "email": "jausions@php.net", 13 | "name": "Philippe Jausions", 14 | "role": "Lead" 15 | } 16 | ], 17 | "license": "BSD-2-Clause", 18 | "homepage": "http://pear.php.net/package/HTTP2", 19 | "support": { 20 | "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=HTTP2", 21 | "source": "https://github.com/pear/HTTP2" 22 | }, 23 | "autoload": { 24 | "psr-0": { 25 | "HTTP2": "./" 26 | } 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^9" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/absoluteURI.inc: -------------------------------------------------------------------------------- 1 | 12 | * @version $Id$ 13 | */ 14 | require_once 'HTTP2.php'; 15 | 16 | // For 4th argument of HTTP2::absoluteURI() method 17 | if (!defined('HTTP2_RELATIVETOSCRIPT')) { 18 | define('HTTP2_RELATIVETOSCRIPT', true); 19 | } 20 | 21 | $tests = array( 22 | // page, protocol, port 23 | array(null, null, null), // Current full URI 24 | array('?new=value', null, null), // Append/replace query string 25 | array('#anchor', null, null), // Anchor target to URI 26 | array('/page.html', null, null), // Web root 27 | array('page.html', null, null), // Relative 28 | array('page.html', 'http', null), // Force HTTP 29 | array('page.html', 'http', 80), // Force HTTP / default port 30 | array('page.html', 'http', 8080), // Force HTTP / port 8080 31 | array('page.html', 'https', null), // Force HTTPS 32 | array('page.html', 'https', 443), // Force HTTPS / default port 33 | array('page.html', null, 8080), // Switch port (same protocol) 34 | array('page.html', 'https', 8888), // Force HTTPS / port 8888 35 | ); 36 | 37 | $http = new HTTP2(); 38 | foreach ($tests as $test) { 39 | list($page, $protocol, $port) = $test; 40 | 41 | echo sprintf('%-20s', implode('|', $test)).' => ' 42 | .$http->absoluteURI($page, $protocol, $port, HTTP2_RELATIVETOSCRIPT) 43 | ."\n"; 44 | } 45 | 46 | ?> -------------------------------------------------------------------------------- /tests/negotiateCharset.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | negotiateCharset() with default 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING= 7 | SERVER_PORT=80 8 | HTTPS=off 9 | REQUEST_URI=/subdir/test.php 10 | SCRIPT_NAME=/subdir/test.php 11 | HTTP_ACCEPT_CHARSET=ISO-8859-1, Big5;q=0.6,utf-8;q=0.7, *;q=0.5 12 | --FILE-- 13 | 22 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 23 | * @link http://pear.php.net/package/HTTP2 24 | */ 25 | require_once 'HTTP2.php'; 26 | 27 | // The --ENV-- Accept sets the following order 28 | // (preferred charsets first) 29 | // 1. ISO-8859-1 (Latin1 - Western Europe) 30 | // 2. UTF-8 31 | // 3. Big5 (Traditional Chinese) 32 | // 3. * (any other) 33 | 34 | $sets = array( 35 | 1 => array( 36 | 'utf-8', 37 | 'big5', 38 | 'iso-8859-1', 39 | 'shift-jis', 40 | ), 41 | 2 => array( 42 | 'utf-8', 43 | 'big5', 44 | 'shift-jis', 45 | ), 46 | 3 => array( 47 | 'Big5', 48 | 'shift-jis', 49 | ), 50 | 4 => array( 51 | 'shift-jis', 52 | ), 53 | 5 => array( 54 | ), 55 | ); 56 | 57 | $http = new HTTP2(); 58 | foreach ($sets as $i => $supported) { 59 | echo $i.' => '. $http->negotiateCharset($supported, 'us-ascii') 60 | ."\n"; 61 | } 62 | 63 | ?> 64 | --EXPECT-- 65 | 1 => iso-8859-1 66 | 2 => utf-8 67 | 3 => Big5 68 | 4 => shift-jis 69 | 5 => us-ascii 70 | -------------------------------------------------------------------------------- /tests/negotiateCharset2.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | negotiateCharset() without any default 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING= 7 | SERVER_PORT=80 8 | HTTPS=off 9 | REQUEST_URI=/subdir/test.php 10 | SCRIPT_NAME=/subdir/test.php 11 | HTTP_ACCEPT_CHARSET=ISO-8859-1, Big5;q=0.6,utf-8;q=0.7 12 | --FILE-- 13 | 22 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 23 | * @link http://pear.php.net/package/HTTP2 24 | */ 25 | require_once 'HTTP2.php'; 26 | 27 | // The --ENV-- Accept sets the following order 28 | // (preferred charsets first) 29 | // 1. ISO-8859-1 (Latin1 - Western Europe) 30 | // 2. UTF-8 31 | // 3. Big5 (Traditional Chinese) 32 | // 3. * (any other) 33 | 34 | $sets = array( 35 | 1 => array( 36 | 'utf-8', 37 | 'big5', 38 | 'iso-8859-1', 39 | 'shift-jis', 40 | ), 41 | 2 => array( 42 | 'utf-8', 43 | 'big5', 44 | 'shift-jis', 45 | ), 46 | 3 => array( 47 | 'Big5', 48 | 'shift-jis', 49 | ), 50 | 4 => array( 51 | 'shift-jis', 52 | ), 53 | 5 => array( 54 | ), 55 | ); 56 | $http = new HTTP2(); 57 | foreach ($sets as $i => $supported) { 58 | echo $i.' => '. $http->negotiateCharset($supported, 'us-ascii') 59 | ."\n"; 60 | } 61 | 62 | ?> 63 | --EXPECT-- 64 | 1 => iso-8859-1 65 | 2 => utf-8 66 | 3 => Big5 67 | 4 => us-ascii 68 | 5 => us-ascii 69 | -------------------------------------------------------------------------------- /tests/negotiateLanguage.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | negotiateLanguage() 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING= 7 | SERVER_PORT=80 8 | HTTPS=off 9 | REQUEST_URI=/subdir/test.php 10 | SCRIPT_NAME=/subdir/test.php 11 | HTTP_ACCEPT_LANGUAGE=es-ES;q=0.7, es; q=0.6 ,fr; q=1.0, en; q=0.5,dk , fr-CH 12 | --FILE-- 13 | 22 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 23 | * @link http://pear.php.net/package/HTTP2 24 | */ 25 | require_once 'HTTP2.php'; 26 | 27 | // The --ENV-- Accept-language gives the following order 28 | // (preferred language first) 29 | // 1. dk 30 | // 2. fr 31 | // 3. es-ES 32 | // 4. es 33 | // 5. en 34 | 35 | $sets = array( 36 | 1 => array( 37 | 'es-ES' => 'x', 38 | 'fr' => true, 39 | 'es' => 1, 40 | 'en' => true, 41 | 'dk' => true, 42 | ), 43 | 2 => array( 44 | 'es-ES' => 'x', 45 | 'fr' => true, 46 | 'es' => 1, 47 | 'en' => true, 48 | ), 49 | 3 => array( 50 | 'es-ES' => 'x', 51 | 'es' => 1, 52 | 'en' => true, 53 | ), 54 | 4 => array( 55 | 'es' => 1, 56 | 'en' => true, 57 | ), 58 | 5 => array( 59 | 'en' => true, 60 | ), 61 | 6 => array( 62 | 'pt-BR' => true, 63 | 'dk' => false, // FALSE makes "dk" entry ignored 64 | ), 65 | 7 => array( 66 | ), 67 | ); 68 | $http = new HTTP2(); 69 | foreach ($sets as $i => $languages) { 70 | echo $i.' => '. $http->negotiateLanguage($languages, 'de')."\n"; 71 | } 72 | 73 | ?> 74 | --EXPECT-- 75 | 1 => dk 76 | 2 => fr 77 | 3 => es-ES 78 | 4 => es 79 | 5 => en 80 | 6 => de 81 | 7 => de 82 | -------------------------------------------------------------------------------- /tests/negotiateMimeType.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | negotiateMimeType() 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING= 7 | SERVER_PORT=80 8 | HTTPS=off 9 | REQUEST_URI=/subdir/test.php 10 | SCRIPT_NAME=/subdir/test.php 11 | HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,text/*;q=0.7,*/*,image/gif; q=0.8, image/jpeg; q=0.6, image/* 12 | --FILE-- 13 | 22 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 23 | * @link http://pear.php.net/package/HTTP2 24 | */ 25 | require_once 'HTTP2.php'; 26 | 27 | // The --ENV-- Accept sets the following order 28 | // (preferred types first) 29 | // 1. text/html 30 | // 2. application/xhtml+xml 31 | // 3. application/xml 32 | // 4. image/gif 33 | // 5. text/* (any text type) 34 | // 6. image/jpeg 35 | // 7. image/* (any image type) 36 | // 8. */* (any type) 37 | 38 | $sets = array( 39 | 1 => array( 40 | 'image/gif', 41 | 'image/png', 42 | 'application/xhtml+xml', 43 | 'application/xml', 44 | 'text/html', 45 | 'image/jpeg', 46 | 'text/plain', 47 | ), 48 | 2 => array( 49 | 'image/gif', 50 | 'image/png', 51 | 'application/xhtml+xml', 52 | 'application/xml', 53 | 'image/jpeg', 54 | 'text/plain', 55 | ), 56 | 3 => array( 57 | 'image/gif', 58 | 'image/png', 59 | 'application/xml', 60 | 'image/jpeg', 61 | 'text/plain', 62 | ), 63 | 4 => array( 64 | 'image/gif', 65 | 'image/png', 66 | 'image/jpeg', 67 | 'text/plain', 68 | ), 69 | 5 => array( 70 | 'image/png', 71 | 'image/jpeg', 72 | 'text/plain', 73 | ), 74 | 6 => array( 75 | 'image/png', 76 | 'image/jpeg', 77 | ), 78 | 7 => array( 79 | 'image/png', 80 | ), 81 | 8 => array( 82 | 'audio/midi', 83 | ), 84 | 9 => array( 85 | ), 86 | ); 87 | 88 | $http = new HTTP2(); 89 | foreach ($sets as $i => $supported) { 90 | echo $i.' => '.$http->negotiateMimeType($supported, 'application/octet-stream') 91 | ."\n"; 92 | } 93 | 94 | ?> 95 | --EXPECT-- 96 | 1 => text/html 97 | 2 => application/xhtml+xml 98 | 3 => application/xml 99 | 4 => image/gif 100 | 5 => text/plain 101 | 6 => image/jpeg 102 | 7 => image/png 103 | 8 => audio/midi 104 | 9 => application/octet-stream 105 | -------------------------------------------------------------------------------- /tests/parseLinks_array.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): link value array 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $out = var_export( 19 | $http->parseLinks( 20 | array( 21 | '<>;a=b;b=c;c=d;d="e"', 22 | '<#>,<##>;' 23 | ) 24 | ), 25 | true 26 | ); 27 | echo preg_replace('#\s+\n#', "\n", $out); 28 | ?> 29 | --EXPECT-- 30 | array ( 31 | 0 => 32 | array ( 33 | '_uri' => '', 34 | 'a' => 'b', 35 | 'b' => 'c', 36 | 'c' => 'd', 37 | 'd' => 'e', 38 | ), 39 | 1 => 40 | array ( 41 | '_uri' => '#', 42 | ), 43 | 2 => 44 | array ( 45 | '_uri' => '##', 46 | ), 47 | ) 48 | -------------------------------------------------------------------------------- /tests/parseLinks_multiple.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): multiple links separated by comma 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $out = var_export($http->parseLinks(', , , , '), true); 19 | echo preg_replace('#\s+\n#', "\n", $out); 20 | ?> 21 | --EXPECT-- 22 | array ( 23 | 0 => 24 | array ( 25 | '_uri' => 'a', 26 | ), 27 | 1 => 28 | array ( 29 | '_uri' => 'b', 30 | ), 31 | 2 => 32 | array ( 33 | '_uri' => 'c', 34 | ), 35 | ) 36 | -------------------------------------------------------------------------------- /tests/parseLinks_real.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): real world examples 3 | --FILE-- 4 | ; rel="http://webmention.org/"', 9 | '; rel="http://webmention.org/"', 10 | '; rel="indieauth"' 11 | ); 12 | $out = var_export($http->parseLinks($links), true); 13 | echo preg_replace('#\s+\n#', "\n", $out); 14 | ?> 15 | --EXPECT-- 16 | array ( 17 | 0 => 18 | array ( 19 | '_uri' => 'http://waterpigs.co.uk/mentions/webmention/', 20 | 'rel' => 21 | array ( 22 | 0 => 'http://webmention.org/', 23 | ), 24 | ), 25 | 1 => 26 | array ( 27 | '_uri' => 'http://aaronparecki.com/webmention.php', 28 | 'rel' => 29 | array ( 30 | 0 => 'http://webmention.org/', 31 | ), 32 | ), 33 | 2 => 34 | array ( 35 | '_uri' => 'https://indieauth.com', 36 | 'rel' => 37 | array ( 38 | 0 => 'indieauth', 39 | ), 40 | ), 41 | ) 42 | -------------------------------------------------------------------------------- /tests/parseLinks_rel-no-quote.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): relation without quotes 3 | --FILE-- 4 | ; rel=shortlink' 9 | ); 10 | $out = var_export($http->parseLinks($links), true); 11 | echo preg_replace('#\s+\n#', "\n", $out); 12 | ?> 13 | --EXPECT-- 14 | array ( 15 | 0 => 16 | array ( 17 | '_uri' => 'http://wp.me/PEmnE-1hd', 18 | 'rel' => 19 | array ( 20 | 0 => 'shortlink', 21 | ), 22 | ), 23 | ) 24 | -------------------------------------------------------------------------------- /tests/parseLinks_rfc5988-examples-1.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): RFC 5988 example 1 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $links = array( 19 | '; rel="previous"; title="previous chapter"', 20 | ); 21 | $out = var_export($http->parseLinks($links), true); 22 | echo preg_replace('#\s+\n#', "\n", $out); 23 | ?> 24 | --EXPECT-- 25 | array ( 26 | 0 => 27 | array ( 28 | '_uri' => 'http://example.com/TheBook/chapter2', 29 | 'rel' => 30 | array ( 31 | 0 => 'previous', 32 | ), 33 | 'title' => 'previous chapter', 34 | ), 35 | ) 36 | -------------------------------------------------------------------------------- /tests/parseLinks_rfc5988-examples-2.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): RFC 5988 example 2 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $out = var_export($http->parseLinks('; rel="http://example.net/foo"'), true); 19 | echo preg_replace('#\s+\n#', "\n", $out); 20 | ?> 21 | --EXPECT-- 22 | array ( 23 | 0 => 24 | array ( 25 | '_uri' => '/', 26 | 'rel' => 27 | array ( 28 | 0 => 'http://example.net/foo', 29 | ), 30 | ), 31 | ) 32 | -------------------------------------------------------------------------------- /tests/parseLinks_rfc5988-examples-3.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): RFC 5988 example 3 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $out = var_export( 19 | $http->parseLinks( 20 | ';rel="previous"; title*=UTF-8\'de\'letztes%20Kapitel,' 21 | ), 22 | true 23 | ); 24 | echo preg_replace('#\s+\n#', "\n", $out); 25 | ?> 26 | --EXPECT-- 27 | array ( 28 | 0 => 29 | array ( 30 | '_uri' => '/TheBook/chapter2', 31 | 'rel' => 32 | array ( 33 | 0 => 'previous', 34 | ), 35 | 'title*' => 36 | array ( 37 | 'de' => 'letztes Kapitel', 38 | ), 39 | ), 40 | ) 41 | -------------------------------------------------------------------------------- /tests/parseLinks_rfc5988-examples-4.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | parseLinks(): RFC 5988 example 4 3 | --FILE-- 4 | 13 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 14 | * @link http://pear.php.net/package/HTTP2 15 | */ 16 | require_once 'HTTP2.php'; 17 | $http = new HTTP2(); 18 | $links = array( 19 | '; rel="next"; title*=UTF-8\'de\'n%c3%a4chstes%20Kapitel,' 20 | . ';rel="start http://example.net/relation/other"', 21 | ); 22 | $out = var_export($http->parseLinks($links), true); 23 | echo preg_replace('#\s+\n#', "\n", $out); 24 | ?> 25 | --EXPECT-- 26 | array ( 27 | 0 => 28 | array ( 29 | '_uri' => '/TheBook/chapter4', 30 | 'rel' => 31 | array ( 32 | 0 => 'next', 33 | ), 34 | 'title*' => 35 | array ( 36 | 'de' => 'nächstes Kapitel', 37 | ), 38 | ), 39 | 1 => 40 | array ( 41 | '_uri' => 'http://example.org/', 42 | 'rel' => 43 | array ( 44 | 0 => 'start', 45 | 1 => 'http://example.net/relation/other', 46 | ), 47 | ), 48 | ) 49 | -------------------------------------------------------------------------------- /tests/test1a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: http://example.org/subdir/test.php/extra_pathinfo/?abc=123 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING=abc=123 7 | SERVER_PORT=80 8 | HTTPS=off 9 | PATH_INFO=/extra_pathinfo/ 10 | REQUEST_URI=/subdir/test.php/extra_pathinfo/?abc=123 11 | SCRIPT_NAME=/subdir/test.php 12 | --FILE-- 13 | 26 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 27 | * @link http://pear.php.net/package/HTTP2 28 | */ 29 | require __DIR__ . '/absoluteURI.inc'; 30 | 31 | ?> 32 | --EXPECT-- 33 | || => http://example.org/subdir/test.php/extra_pathinfo/?abc=123 34 | ?new=value|| => http://example.org/subdir/test.php/extra_pathinfo/?new=value 35 | #anchor|| => http://example.org/subdir/test.php/extra_pathinfo/?abc=123#anchor 36 | /page.html|| => http://example.org/page.html 37 | page.html|| => http://example.org/subdir/page.html 38 | page.html|http| => http://example.org/subdir/page.html 39 | page.html|http|80 => http://example.org/subdir/page.html 40 | page.html|http|8080 => http://example.org:8080/subdir/page.html 41 | page.html|https| => https://example.org/subdir/page.html 42 | page.html|https|443 => https://example.org/subdir/page.html 43 | page.html||8080 => http://example.org:8080/subdir/page.html 44 | page.html|https|8888 => https://example.org:8888/subdir/page.html 45 | -------------------------------------------------------------------------------- /tests/test2a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: http://example.org/subdir/test.php/extra_pathinfo?abc=123 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING=abc=123 7 | SERVER_PORT=80 8 | PATH_INFO=/extra_pathinfo 9 | REQUEST_URI=/subdir/test.php/extra_pathinfo?abc=123 10 | SCRIPT_NAME=/subdir/test.php 11 | --FILE-- 12 | 24 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 25 | * @link http://pear.php.net/package/HTTP2 26 | */ 27 | require __DIR__ . '/absoluteURI.inc'; 28 | 29 | ?> 30 | --EXPECT-- 31 | || => http://example.org/subdir/test.php/extra_pathinfo?abc=123 32 | ?new=value|| => http://example.org/subdir/test.php/extra_pathinfo?new=value 33 | #anchor|| => http://example.org/subdir/test.php/extra_pathinfo?abc=123#anchor 34 | /page.html|| => http://example.org/page.html 35 | page.html|| => http://example.org/subdir/page.html 36 | page.html|http| => http://example.org/subdir/page.html 37 | page.html|http|80 => http://example.org/subdir/page.html 38 | page.html|http|8080 => http://example.org:8080/subdir/page.html 39 | page.html|https| => https://example.org/subdir/page.html 40 | page.html|https|443 => https://example.org/subdir/page.html 41 | page.html||8080 => http://example.org:8080/subdir/page.html 42 | page.html|https|8888 => https://example.org:8888/subdir/page.html 43 | -------------------------------------------------------------------------------- /tests/test3a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: http://example.org/subdir/test.php/?abc=123 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | QUERY_STRING=abc=123 7 | SERVER_PORT=80 8 | PATH_INFO=/ 9 | REQUEST_URI=/subdir/test.php/?abc=123 10 | SCRIPT_NAME=/subdir/test.php 11 | --FILE-- 12 | 24 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 25 | * @link http://pear.php.net/package/HTTP2 26 | */ 27 | require __DIR__ . '/absoluteURI.inc'; 28 | 29 | ?> 30 | --EXPECT-- 31 | || => http://example.org/subdir/test.php/?abc=123 32 | ?new=value|| => http://example.org/subdir/test.php/?new=value 33 | #anchor|| => http://example.org/subdir/test.php/?abc=123#anchor 34 | /page.html|| => http://example.org/page.html 35 | page.html|| => http://example.org/subdir/page.html 36 | page.html|http| => http://example.org/subdir/page.html 37 | page.html|http|80 => http://example.org/subdir/page.html 38 | page.html|http|8080 => http://example.org:8080/subdir/page.html 39 | page.html|https| => https://example.org/subdir/page.html 40 | page.html|https|443 => https://example.org/subdir/page.html 41 | page.html||8080 => http://example.org:8080/subdir/page.html 42 | page.html|https|8888 => https://example.org:8888/subdir/page.html 43 | -------------------------------------------------------------------------------- /tests/test4a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: https://example.org/subdir/test.php?abc=123 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | HTTPS=on 6 | SERVER_NAME=example.org 7 | QUERY_STRING=abc=123 8 | SERVER_PORT=443 9 | PATH_INFO= 10 | REQUEST_URI=/subdir/test.php?abc=123 11 | SCRIPT_NAME=/subdir/test.php 12 | --FILE-- 13 | 25 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 26 | * @link http://pear.php.net/package/HTTP2 27 | */ 28 | require __DIR__ . '/absoluteURI.inc'; 29 | 30 | ?> 31 | --EXPECT-- 32 | || => https://example.org/subdir/test.php?abc=123 33 | ?new=value|| => https://example.org/subdir/test.php?new=value 34 | #anchor|| => https://example.org/subdir/test.php?abc=123#anchor 35 | /page.html|| => https://example.org/page.html 36 | page.html|| => https://example.org/subdir/page.html 37 | page.html|http| => http://example.org/subdir/page.html 38 | page.html|http|80 => http://example.org/subdir/page.html 39 | page.html|http|8080 => http://example.org:8080/subdir/page.html 40 | page.html|https| => https://example.org/subdir/page.html 41 | page.html|https|443 => https://example.org/subdir/page.html 42 | page.html||8080 => https://example.org:8080/subdir/page.html 43 | page.html|https|8888 => https://example.org:8888/subdir/page.html 44 | -------------------------------------------------------------------------------- /tests/test5a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: https://example.org:8443/subdir/test.php?abc=123 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | HTTPS=on 6 | SERVER_NAME=example.org 7 | QUERY_STRING=abc=123 8 | SERVER_PORT=8443 9 | REQUEST_URI=/subdir/test.php?abc=123 10 | SCRIPT_NAME=/subdir/test.php 11 | --FILE-- 12 | 21 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 22 | * @link http://pear.php.net/package/HTTP2 23 | */ 24 | require __DIR__ . '/absoluteURI.inc'; 25 | 26 | ?> 27 | --EXPECT-- 28 | || => https://example.org:8443/subdir/test.php?abc=123 29 | ?new=value|| => https://example.org:8443/subdir/test.php?new=value 30 | #anchor|| => https://example.org:8443/subdir/test.php?abc=123#anchor 31 | /page.html|| => https://example.org:8443/page.html 32 | page.html|| => https://example.org:8443/subdir/page.html 33 | page.html|http| => http://example.org/subdir/page.html 34 | page.html|http|80 => http://example.org/subdir/page.html 35 | page.html|http|8080 => http://example.org:8080/subdir/page.html 36 | page.html|https| => https://example.org/subdir/page.html 37 | page.html|https|443 => https://example.org/subdir/page.html 38 | page.html||8080 => https://example.org:8080/subdir/page.html 39 | page.html|https|8888 => https://example.org:8888/subdir/page.html 40 | -------------------------------------------------------------------------------- /tests/test6a.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | absoluteURI() URL: http://example.org/subdir/ 3 | --ENV-- 4 | HTTP_HOST=example.org 5 | SERVER_NAME=example.org 6 | SERVER_PORT=80 7 | REQUEST_URI=/subdir/ 8 | SCRIPT_NAME=/subdir/index.php 9 | --FILE-- 10 | 20 | * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 21 | * @link http://pear.php.net/package/HTTP2 22 | */ 23 | require __DIR__ . '/absoluteURI.inc'; 24 | 25 | ?> 26 | --EXPECT-- 27 | || => http://example.org/subdir/ 28 | ?new=value|| => http://example.org/subdir/?new=value 29 | #anchor|| => http://example.org/subdir/#anchor 30 | /page.html|| => http://example.org/page.html 31 | page.html|| => http://example.org/subdir/page.html 32 | page.html|http| => http://example.org/subdir/page.html 33 | page.html|http|80 => http://example.org/subdir/page.html 34 | page.html|http|8080 => http://example.org:8080/subdir/page.html 35 | page.html|https| => https://example.org/subdir/page.html 36 | page.html|https|443 => https://example.org/subdir/page.html 37 | page.html||8080 => http://example.org:8080/subdir/page.html 38 | page.html|https|8888 => https://example.org:8888/subdir/page.html 39 | --------------------------------------------------------------------------------