[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Part of the Joomla Framework Application Package 4 * 5 * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. 6 * @license GNU General Public License version 2 or later; see LICENSE 7 */ 8 9 namespace Joomla\Application; 10 11 use Joomla\Application\Exception\UnableToWriteBody; 12 use Joomla\Input\Input; 13 use Joomla\Registry\Registry; 14 use Joomla\Uri\Uri; 15 use Laminas\Diactoros\Response; 16 use Laminas\Diactoros\Stream; 17 use Psr\Http\Message\ResponseInterface; 18 19 /** 20 * Base class for a Joomla! Web application. 21 * 22 * @since 1.0 23 * 24 * @property-read Input $input The application input object 25 */ 26 abstract class AbstractWebApplication extends AbstractApplication implements WebApplicationInterface 27 { 28 /** 29 * The application input object. 30 * 31 * @var Input 32 * @since 1.0 33 */ 34 protected $input; 35 36 /** 37 * Character encoding string. 38 * 39 * @var string 40 * @since 1.0 41 */ 42 public $charSet = 'utf-8'; 43 44 /** 45 * Response mime type. 46 * 47 * @var string 48 * @since 1.0 49 */ 50 public $mimeType = 'text/html'; 51 52 /** 53 * HTTP protocol version. 54 * 55 * @var string 56 * @since 1.9.0 57 */ 58 public $httpVersion = '1.1'; 59 60 /** 61 * The body modified date for response headers. 62 * 63 * @var \DateTime 64 * @since 1.0 65 */ 66 public $modifiedDate; 67 68 /** 69 * The application client object. 70 * 71 * @var Web\WebClient 72 * @since 1.0 73 */ 74 public $client; 75 76 /** 77 * The application response object. 78 * 79 * @var ResponseInterface 80 * @since 1.0 81 */ 82 protected $response; 83 84 /** 85 * Is caching enabled? 86 * 87 * @var boolean 88 * @since 2.0.0 89 */ 90 private $cacheable = false; 91 92 /** 93 * A map of integer HTTP response codes to the full HTTP Status for the headers. 94 * 95 * @var array 96 * @since 1.6.0 97 * @link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 98 */ 99 private $responseMap = [ 100 100 => 'HTTP/{version} 100 Continue', 101 101 => 'HTTP/{version} 101 Switching Protocols', 102 102 => 'HTTP/{version} 102 Processing', 103 200 => 'HTTP/{version} 200 OK', 104 201 => 'HTTP/{version} 201 Created', 105 202 => 'HTTP/{version} 202 Accepted', 106 203 => 'HTTP/{version} 203 Non-Authoritative Information', 107 204 => 'HTTP/{version} 204 No Content', 108 205 => 'HTTP/{version} 205 Reset Content', 109 206 => 'HTTP/{version} 206 Partial Content', 110 207 => 'HTTP/{version} 207 Multi-Status', 111 208 => 'HTTP/{version} 208 Already Reported', 112 226 => 'HTTP/{version} 226 IM Used', 113 300 => 'HTTP/{version} 300 Multiple Choices', 114 301 => 'HTTP/{version} 301 Moved Permanently', 115 302 => 'HTTP/{version} 302 Found', 116 303 => 'HTTP/{version} 303 See other', 117 304 => 'HTTP/{version} 304 Not Modified', 118 305 => 'HTTP/{version} 305 Use Proxy', 119 306 => 'HTTP/{version} 306 (Unused)', 120 307 => 'HTTP/{version} 307 Temporary Redirect', 121 308 => 'HTTP/{version} 308 Permanent Redirect', 122 400 => 'HTTP/{version} 400 Bad Request', 123 401 => 'HTTP/{version} 401 Unauthorized', 124 402 => 'HTTP/{version} 402 Payment Required', 125 403 => 'HTTP/{version} 403 Forbidden', 126 404 => 'HTTP/{version} 404 Not Found', 127 405 => 'HTTP/{version} 405 Method Not Allowed', 128 406 => 'HTTP/{version} 406 Not Acceptable', 129 407 => 'HTTP/{version} 407 Proxy Authentication Required', 130 408 => 'HTTP/{version} 408 Request Timeout', 131 409 => 'HTTP/{version} 409 Conflict', 132 410 => 'HTTP/{version} 410 Gone', 133 411 => 'HTTP/{version} 411 Length Required', 134 412 => 'HTTP/{version} 412 Precondition Failed', 135 413 => 'HTTP/{version} 413 Payload Too Large', 136 414 => 'HTTP/{version} 414 URI Too Long', 137 415 => 'HTTP/{version} 415 Unsupported Media Type', 138 416 => 'HTTP/{version} 416 Range Not Satisfiable', 139 417 => 'HTTP/{version} 417 Expectation Failed', 140 418 => 'HTTP/{version} 418 I\'m a teapot', 141 421 => 'HTTP/{version} 421 Misdirected Request', 142 422 => 'HTTP/{version} 422 Unprocessable Entity', 143 423 => 'HTTP/{version} 423 Locked', 144 424 => 'HTTP/{version} 424 Failed Dependency', 145 426 => 'HTTP/{version} 426 Upgrade Required', 146 428 => 'HTTP/{version} 428 Precondition Required', 147 429 => 'HTTP/{version} 429 Too Many Requests', 148 431 => 'HTTP/{version} 431 Request Header Fields Too Large', 149 451 => 'HTTP/{version} 451 Unavailable For Legal Reasons', 150 500 => 'HTTP/{version} 500 Internal Server Error', 151 501 => 'HTTP/{version} 501 Not Implemented', 152 502 => 'HTTP/{version} 502 Bad Gateway', 153 503 => 'HTTP/{version} 503 Service Unavailable', 154 504 => 'HTTP/{version} 504 Gateway Timeout', 155 505 => 'HTTP/{version} 505 HTTP Version Not Supported', 156 506 => 'HTTP/{version} 506 Variant Also Negotiates', 157 507 => 'HTTP/{version} 507 Insufficient Storage', 158 508 => 'HTTP/{version} 508 Loop Detected', 159 510 => 'HTTP/{version} 510 Not Extended', 160 511 => 'HTTP/{version} 511 Network Authentication Required', 161 ]; 162 163 /** 164 * Class constructor. 165 * 166 * @param Input $input An optional argument to provide dependency injection for the application's 167 * input object. If the argument is an Input object that object will become 168 * the application's input object, otherwise a default input object is 169 * created. 170 * @param Registry $config An optional argument to provide dependency injection for the application's 171 * config object. If the argument is a Registry object that object will 172 * become the application's config object, otherwise a default config object 173 * is created. 174 * @param Web\WebClient $client An optional argument to provide dependency injection for the application's 175 * client object. If the argument is a Web\WebClient object that object will 176 * become the application's client object, otherwise a default client object 177 * is created. 178 * @param ResponseInterface $response An optional argument to provide dependency injection for the application's 179 * response object. If the argument is a ResponseInterface object that object 180 * will become the application's response object, otherwise a default response 181 * object is created. 182 * 183 * @since 1.0 184 */ 185 public function __construct(Input $input = null, Registry $config = null, Web\WebClient $client = null, ResponseInterface $response = null) 186 { 187 $this->input = $input ?: new Input; 188 $this->client = $client ?: new Web\WebClient; 189 190 // Setup the response object. 191 if (!$response) 192 { 193 $response = new Response; 194 } 195 196 $this->setResponse($response); 197 198 // Call the constructor as late as possible (it runs `initialise`). 199 parent::__construct($config); 200 201 // Set the system URIs. 202 $this->loadSystemUris(); 203 } 204 205 /** 206 * Magic method to access properties of the application. 207 * 208 * @param string $name The name of the property. 209 * 210 * @return mixed A value if the property name is valid, null otherwise. 211 * 212 * @since 2.0.0 213 * @deprecated 3.0 This is a B/C proxy for deprecated read accesses 214 */ 215 public function __get($name) 216 { 217 switch ($name) 218 { 219 case 'input': 220 trigger_deprecation( 221 'joomla/application', 222 '2.0.0', 223 'Accessing the input property of %s is deprecated, use the %s::getInput() method instead.', 224 self::class, 225 self::class 226 ); 227 228 return $this->getInput(); 229 230 default: 231 $trace = debug_backtrace(); 232 trigger_error( 233 sprintf( 234 'Undefined property via __get(): %1$s in %2$s on line %3$s', 235 $name, 236 $trace[0]['file'], 237 $trace[0]['line'] 238 ), 239 E_USER_NOTICE 240 ); 241 } 242 } 243 244 /** 245 * Execute the application. 246 * 247 * @return void 248 * 249 * @since 1.0 250 */ 251 public function execute() 252 { 253 try 254 { 255 $this->dispatchEvent(ApplicationEvents::BEFORE_EXECUTE); 256 257 // Perform application routines. 258 $this->doExecute(); 259 260 $this->dispatchEvent(ApplicationEvents::AFTER_EXECUTE); 261 262 // If gzip compression is enabled in configuration and the server is compliant, compress the output. 263 if ($this->get('gzip') && !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler')) 264 { 265 $this->compress(); 266 } 267 } 268 catch (\Throwable $throwable) 269 { 270 $this->dispatchEvent(ApplicationEvents::ERROR, new Event\ApplicationErrorEvent($throwable, $this)); 271 } 272 273 $this->dispatchEvent(ApplicationEvents::BEFORE_RESPOND); 274 275 // Send the application response. 276 $this->respond(); 277 278 $this->dispatchEvent(ApplicationEvents::AFTER_RESPOND); 279 } 280 281 /** 282 * Checks the accept encoding of the browser and compresses the data before sending it to the client if possible. 283 * 284 * @return void 285 * 286 * @since 1.0 287 */ 288 protected function compress() 289 { 290 // Supported compression encodings. 291 $supported = [ 292 'x-gzip' => 'gz', 293 'gzip' => 'gz', 294 'deflate' => 'deflate', 295 ]; 296 297 // Get the supported encoding. 298 $encodings = array_intersect($this->client->encodings, array_keys($supported)); 299 300 // If no supported encoding is detected do nothing and return. 301 if (empty($encodings)) 302 { 303 return; 304 } 305 306 // Verify that headers have not yet been sent, and that our connection is still alive. 307 if ($this->checkHeadersSent() || !$this->checkConnectionAlive()) 308 { 309 return; 310 } 311 312 // Iterate through the encodings and attempt to compress the data using any found supported encodings. 313 foreach ($encodings as $encoding) 314 { 315 if (($supported[$encoding] == 'gz') || ($supported[$encoding] == 'deflate')) 316 { 317 // Verify that the server supports gzip compression before we attempt to gzip encode the data. 318 // @codeCoverageIgnoreStart 319 if (!\extension_loaded('zlib') || ini_get('zlib.output_compression')) 320 { 321 continue; 322 } 323 324 // @codeCoverageIgnoreEnd 325 326 // Attempt to gzip encode the data with an optimal level 4. 327 $data = $this->getBody(); 328 $gzdata = gzencode($data, 4, ($supported[$encoding] == 'gz') ? FORCE_GZIP : FORCE_DEFLATE); 329 330 // If there was a problem encoding the data just try the next encoding scheme. 331 // @codeCoverageIgnoreStart 332 if ($gzdata === false) 333 { 334 continue; 335 } 336 337 // @codeCoverageIgnoreEnd 338 339 // Set the encoding headers. 340 $this->setHeader('Content-Encoding', $encoding); 341 $this->setHeader('Vary', 'Accept-Encoding'); 342 $this->setHeader('X-Content-Encoded-By', 'Joomla'); 343 344 // Replace the output with the encoded data. 345 $this->setBody($gzdata); 346 347 // Compression complete, let's break out of the loop. 348 break; 349 } 350 } 351 } 352 353 /** 354 * Method to send the application response to the client. All headers will be sent prior to the main application output data. 355 * 356 * @return void 357 * 358 * @since 1.0 359 */ 360 protected function respond() 361 { 362 // Send the content-type header. 363 if (!$this->getResponse()->hasHeader('Content-Type')) 364 { 365 $this->setHeader('Content-Type', $this->mimeType . '; charset=' . $this->charSet); 366 } 367 368 // If the response is set to uncachable, we need to set some appropriate headers so browsers don't cache the response. 369 if (!$this->allowCache()) 370 { 371 // Expires in the past. 372 $this->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true); 373 374 // Always modified. 375 $this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true); 376 $this->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false); 377 378 // HTTP 1.0 379 $this->setHeader('Pragma', 'no-cache'); 380 } 381 else 382 { 383 // Expires. 384 if (!$this->getResponse()->hasHeader('Expires')) 385 { 386 $this->setHeader('Expires', gmdate('D, d M Y H:i:s', time() + 900) . ' GMT'); 387 } 388 389 // Last modified. 390 if (!$this->getResponse()->hasHeader('Last-Modified') && $this->modifiedDate instanceof \DateTime) 391 { 392 $this->modifiedDate->setTimezone(new \DateTimeZone('UTC')); 393 $this->setHeader('Last-Modified', $this->modifiedDate->format('D, d M Y H:i:s') . ' GMT'); 394 } 395 } 396 397 // Make sure there is a status header already otherwise generate it from the response 398 if (!$this->getResponse()->hasHeader('Status')) 399 { 400 $this->setHeader('Status', (string) $this->getResponse()->getStatusCode()); 401 } 402 403 $this->sendHeaders(); 404 405 echo $this->getBody(); 406 } 407 408 /** 409 * Method to get the application input object. 410 * 411 * @return Input 412 * 413 * @since 2.0.0 414 */ 415 public function getInput(): Input 416 { 417 return $this->input; 418 } 419 420 /** 421 * Redirect to another URL. 422 * 423 * If the headers have not been sent the redirect will be accomplished using a "301 Moved Permanently" or "303 See Other" code in the header 424 * pointing to the new location. If the headers have already been sent this will be accomplished using a JavaScript statement. 425 * 426 * @param string $url The URL to redirect to. Can only be http/https URL 427 * @param integer|boolean $status The HTTP status code to be provided. 303 is assumed by default. 428 * 429 * @return void 430 * 431 * @since 1.0 432 * @throws \InvalidArgumentException 433 */ 434 public function redirect($url, $status = 303) 435 { 436 // Check for relative internal links. 437 if (preg_match('#^index\.php#', $url)) 438 { 439 $url = $this->get('uri.base.full') . $url; 440 } 441 442 // Perform a basic sanity check to make sure we don't have any CRLF garbage. 443 $url = preg_split("/[\r\n]/", $url); 444 $url = $url[0]; 445 446 /* 447 * Here we need to check and see if the URL is relative or absolute. Essentially, do we need to 448 * prepend the URL with our base URL for a proper redirect. The rudimentary way we are looking 449 * at this is to simply check whether or not the URL string has a valid scheme or not. 450 */ 451 if (!preg_match('#^[a-z]+\://#i', $url)) 452 { 453 // Get a Uri instance for the requested URI. 454 $uri = new Uri($this->get('uri.request')); 455 456 // Get a base URL to prepend from the requested URI. 457 $prefix = $uri->toString(['scheme', 'user', 'pass', 'host', 'port']); 458 459 // We just need the prefix since we have a path relative to the root. 460 if ($url[0] == '/') 461 { 462 $url = $prefix . $url; 463 } 464 else 465 { 466 // It's relative to where we are now, so lets add that. 467 $parts = explode('/', $uri->toString(['path'])); 468 array_pop($parts); 469 $path = implode('/', $parts) . '/'; 470 $url = $prefix . $path . $url; 471 } 472 } 473 474 // If the headers have already been sent we need to send the redirect statement via JavaScript. 475 if ($this->checkHeadersSent()) 476 { 477 echo '<script>document.location.href=' . json_encode($url) . ";</script>\n"; 478 } 479 // We have to use a JavaScript redirect here because MSIE doesn't play nice with UTF-8 URLs. 480 elseif (($this->client->engine == Web\WebClient::TRIDENT) && !static::isAscii($url)) 481 { 482 $html = '<html><head>'; 483 $html .= '<meta http-equiv="content-type" content="text/html; charset=' . $this->charSet . '" />'; 484 $html .= '<script>document.location.href=' . json_encode($url) . ';</script>'; 485 $html .= '</head><body></body></html>'; 486 487 echo $html; 488 } 489 else 490 { 491 // Check if we have a boolean for the status variable for compatability with v1 of the framework 492 // @deprecated 3.0 493 if (\is_bool($status)) 494 { 495 trigger_deprecation( 496 'joomla/application', 497 '2.0.0', 498 'Passing a boolean value for the $status argument in %s() is deprecated, an integer should be passed instead.', 499 __METHOD__ 500 ); 501 502 $status = $status ? 301 : 303; 503 } 504 505 if (!\is_int($status) && !$this->isRedirectState($status)) 506 { 507 throw new \InvalidArgumentException('You have not supplied a valid HTTP status code'); 508 } 509 510 // All other cases use the more efficient HTTP header for redirection. 511 $this->setHeader('Status', (string) $status, true); 512 $this->setHeader('Location', $url, true); 513 } 514 515 $this->dispatchEvent(ApplicationEvents::BEFORE_RESPOND); 516 517 // Set appropriate headers 518 $this->respond(); 519 520 $this->dispatchEvent(ApplicationEvents::AFTER_RESPOND); 521 522 // Close the application after the redirect. 523 $this->close(); 524 } 525 526 /** 527 * Set/get cachable state for the response. 528 * 529 * If $allow is set, sets the cachable state of the response. Always returns the current state. 530 * 531 * @param boolean $allow True to allow browser caching. 532 * 533 * @return boolean 534 * 535 * @since 1.0 536 */ 537 public function allowCache($allow = null) 538 { 539 if ($allow !== null) 540 { 541 $this->cacheable = (bool) $allow; 542 } 543 544 return $this->cacheable; 545 } 546 547 /** 548 * Method to set a response header. 549 * 550 * If the replace flag is set then all headers with the given name will be replaced by the new one. 551 * The headers are stored in an internal array to be sent when the site is sent to the browser. 552 * 553 * @param string $name The name of the header to set. 554 * @param string $value The value of the header to set. 555 * @param boolean $replace True to replace any headers with the same name. 556 * 557 * @return $this 558 * 559 * @since 1.0 560 */ 561 public function setHeader($name, $value, $replace = false) 562 { 563 // Sanitize the input values. 564 $name = (string) $name; 565 $value = (string) $value; 566 $response = $this->getResponse(); 567 568 // If the replace flag is set, unset all known headers with the given name. 569 if ($replace && $response->hasHeader($name)) 570 { 571 $response = $response->withoutHeader($name); 572 } 573 574 // Add the header to the internal array. 575 $this->setResponse($response->withAddedHeader($name, $value)); 576 577 return $this; 578 } 579 580 /** 581 * Method to get the array of response headers to be sent when the response is sent to the client. 582 * 583 * @return array 584 * 585 * @since 1.0 586 */ 587 public function getHeaders() 588 { 589 $return = []; 590 591 foreach ($this->getResponse()->getHeaders() as $name => $values) 592 { 593 foreach ($values as $value) 594 { 595 $return[] = ['name' => $name, 'value' => $value]; 596 } 597 } 598 599 return $return; 600 } 601 602 /** 603 * Method to clear any set response headers. 604 * 605 * @return $this 606 * 607 * @since 1.0 608 */ 609 public function clearHeaders() 610 { 611 $response = $this->getResponse(); 612 613 foreach ($response->getHeaders() as $name => $values) 614 { 615 $response = $response->withoutHeader($name); 616 } 617 618 $this->setResponse($response); 619 620 return $this; 621 } 622 623 /** 624 * Send the response headers. 625 * 626 * @return $this 627 * 628 * @since 1.0 629 */ 630 public function sendHeaders() 631 { 632 if (!$this->checkHeadersSent()) 633 { 634 foreach ($this->getHeaders() as $header) 635 { 636 if (strtolower($header['name']) == 'status') 637 { 638 // 'status' headers indicate an HTTP status, and need to be handled slightly differently 639 $status = $this->getHttpStatusValue($header['value']); 640 641 $this->header($status, true, (int) $header['value']); 642 } 643 else 644 { 645 $this->header($header['name'] . ': ' . $header['value']); 646 } 647 } 648 } 649 650 return $this; 651 } 652 653 /** 654 * Set body content. If body content already defined, this will replace it. 655 * 656 * @param string $content The content to set as the response body. 657 * 658 * @return $this 659 * 660 * @since 1.0 661 */ 662 public function setBody($content) 663 { 664 $stream = new Stream('php://memory', 'rw'); 665 $stream->write((string) $content); 666 $this->setResponse($this->getResponse()->withBody($stream)); 667 668 return $this; 669 } 670 671 /** 672 * Prepend content to the body content 673 * 674 * @param string $content The content to prepend to the response body. 675 * 676 * @return $this 677 * 678 * @since 1.0 679 */ 680 public function prependBody($content) 681 { 682 $currentBody = $this->getResponse()->getBody(); 683 684 if (!$currentBody->isReadable()) 685 { 686 throw new UnableToWriteBody; 687 } 688 689 $stream = new Stream('php://memory', 'rw'); 690 $stream->write((string) $content . (string) $currentBody); 691 $this->setResponse($this->getResponse()->withBody($stream)); 692 693 return $this; 694 } 695 696 /** 697 * Append content to the body content 698 * 699 * @param string $content The content to append to the response body. 700 * 701 * @return $this 702 * 703 * @since 1.0 704 */ 705 public function appendBody($content) 706 { 707 $currentStream = $this->getResponse()->getBody(); 708 709 if ($currentStream->isWritable()) 710 { 711 $currentStream->write((string) $content); 712 $this->setResponse($this->getResponse()->withBody($currentStream)); 713 } 714 elseif ($currentStream->isReadable()) 715 { 716 $stream = new Stream('php://memory', 'rw'); 717 $stream->write((string) $currentStream . (string) $content); 718 $this->setResponse($this->getResponse()->withBody($stream)); 719 } 720 else 721 { 722 throw new UnableToWriteBody; 723 } 724 725 return $this; 726 } 727 728 /** 729 * Return the body content 730 * 731 * @return string The response body as a string. 732 * 733 * @since 1.0 734 */ 735 public function getBody() 736 { 737 return (string) $this->getResponse()->getBody(); 738 } 739 740 /** 741 * Get the PSR-7 Response Object. 742 * 743 * @return ResponseInterface 744 * 745 * @since 2.0.0 746 */ 747 public function getResponse(): ResponseInterface 748 { 749 return $this->response; 750 } 751 752 /** 753 * Check if a given value can be successfully mapped to a valid http status value 754 * 755 * @param string|int $value The given status as int or string 756 * 757 * @return string 758 * 759 * @since 1.8.0 760 */ 761 protected function getHttpStatusValue($value) 762 { 763 $code = (int) $value; 764 765 if (array_key_exists($code, $this->responseMap)) 766 { 767 $value = $this->responseMap[$code]; 768 } 769 else 770 { 771 $value = 'HTTP/{version} ' . $code; 772 } 773 774 return str_replace('{version}', $this->httpVersion, $value); 775 } 776 777 /** 778 * Check if the value is a valid HTTP status code 779 * 780 * @param integer $code The potential status code 781 * 782 * @return boolean 783 * 784 * @since 1.8.1 785 */ 786 public function isValidHttpStatus($code) 787 { 788 return array_key_exists($code, $this->responseMap); 789 } 790 791 /** 792 * Method to check the current client connection status to ensure that it is alive. We are 793 * wrapping this to isolate the connection_status() function from our code base for testing reasons. 794 * 795 * @return boolean True if the connection is valid and normal. 796 * 797 * @codeCoverageIgnore 798 * @see connection_status() 799 * @since 1.0 800 */ 801 protected function checkConnectionAlive() 802 { 803 return connection_status() === CONNECTION_NORMAL; 804 } 805 806 /** 807 * Method to check to see if headers have already been sent. 808 * 809 * @return boolean True if the headers have already been sent. 810 * 811 * @codeCoverageIgnore 812 * @see headers_sent() 813 * @since 1.0 814 */ 815 protected function checkHeadersSent() 816 { 817 return headers_sent(); 818 } 819 820 /** 821 * Method to detect the requested URI from server environment variables. 822 * 823 * @return string The requested URI 824 * 825 * @since 1.0 826 */ 827 protected function detectRequestUri() 828 { 829 // First we need to detect the URI scheme. 830 $scheme = $this->isSslConnection() ? 'https://' : 'http://'; 831 832 /* 833 * There are some differences in the way that Apache and IIS populate server environment variables. To 834 * properly detect the requested URI we need to adjust our algorithm based on whether or not we are getting 835 * information from Apache or IIS. 836 */ 837 838 $phpSelf = $this->input->server->getString('PHP_SELF', ''); 839 $requestUri = $this->input->server->getString('REQUEST_URI', ''); 840 841 // If PHP_SELF and REQUEST_URI are both populated then we will assume "Apache Mode". 842 if (!empty($phpSelf) && !empty($requestUri)) 843 { 844 // The URI is built from the HTTP_HOST and REQUEST_URI environment variables in an Apache environment. 845 $uri = $scheme . $this->input->server->getString('HTTP_HOST') . $requestUri; 846 } 847 else 848 { 849 // If not in "Apache Mode" we will assume that we are in an IIS environment and proceed. 850 // IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable... thanks, MS 851 $uri = $scheme . $this->input->server->getString('HTTP_HOST') . $this->input->server->getString('SCRIPT_NAME'); 852 $queryHost = $this->input->server->getString('QUERY_STRING', ''); 853 854 // If the QUERY_STRING variable exists append it to the URI string. 855 if (!empty($queryHost)) 856 { 857 $uri .= '?' . $queryHost; 858 } 859 } 860 861 return trim($uri); 862 } 863 864 /** 865 * Method to send a header to the client. 866 * 867 * @param string $string The header string. 868 * @param boolean $replace The optional replace parameter indicates whether the header should replace a previous similar header, or add 869 * a second header of the same type. 870 * @param integer $code Forces the HTTP response code to the specified value. Note that this parameter only has an effect if the string 871 * is not empty. 872 * 873 * @return void 874 * 875 * @codeCoverageIgnore 876 * @see header() 877 * @since 1.0 878 */ 879 protected function header($string, $replace = true, $code = null) 880 { 881 if ($code === null) 882 { 883 $code = 0; 884 } 885 886 header(str_replace(\chr(0), '', $string), $replace, $code); 887 } 888 889 /** 890 * Set the PSR-7 Response Object. 891 * 892 * @param ResponseInterface $response The response object 893 * 894 * @return void 895 * 896 * @since 2.0.0 897 */ 898 public function setResponse(ResponseInterface $response): void 899 { 900 $this->response = $response; 901 } 902 903 /** 904 * Checks if a state is a redirect state 905 * 906 * @param integer $state The HTTP status code. 907 * 908 * @return boolean 909 * 910 * @since 1.8.0 911 */ 912 protected function isRedirectState($state) 913 { 914 $state = (int) $state; 915 916 return $state > 299 && $state < 400 && array_key_exists($state, $this->responseMap); 917 } 918 919 /** 920 * Determine if we are using a secure (SSL) connection. 921 * 922 * @return boolean True if using SSL, false if not. 923 * 924 * @since 1.0 925 */ 926 public function isSslConnection() 927 { 928 $serverSSLVar = $this->input->server->getString('HTTPS', ''); 929 930 if (!empty($serverSSLVar) && strtolower($serverSSLVar) !== 'off') 931 { 932 return true; 933 } 934 935 $serverForwarderProtoVar = $this->input->server->getString('HTTP_X_FORWARDED_PROTO', ''); 936 937 return !empty($serverForwarderProtoVar) && strtolower($serverForwarderProtoVar) === 'https'; 938 } 939 940 /** 941 * Method to load the system URI strings for the application. 942 * 943 * @param string $requestUri An optional request URI to use instead of detecting one from the server environment variables. 944 * 945 * @return void 946 * 947 * @since 1.0 948 */ 949 protected function loadSystemUris($requestUri = null) 950 { 951 // Set the request URI. 952 if (!empty($requestUri)) 953 { 954 $this->set('uri.request', $requestUri); 955 } 956 else 957 { 958 $this->set('uri.request', $this->detectRequestUri()); 959 } 960 961 // Check to see if an explicit base URI has been set. 962 $siteUri = trim($this->get('site_uri')); 963 964 if ($siteUri != '') 965 { 966 $uri = new Uri($siteUri); 967 $path = $uri->toString(['path']); 968 } 969 else 970 { 971 // No explicit base URI was set so we need to detect it. Start with the requested URI. 972 $uri = new Uri($this->get('uri.request')); 973 974 $requestUri = $this->input->server->getString('REQUEST_URI', ''); 975 976 // If we are working from a CGI SAPI with the 'cgi.fix_pathinfo' directive disabled we use PHP_SELF. 977 if (strpos(PHP_SAPI, 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($requestUri)) 978 { 979 // We aren't expecting PATH_INFO within PHP_SELF so this should work. 980 $path = \dirname($this->input->server->getString('PHP_SELF', '')); 981 } 982 else 983 { 984 // Pretty much everything else should be handled with SCRIPT_NAME. 985 $path = \dirname($this->input->server->getString('SCRIPT_NAME', '')); 986 } 987 } 988 989 // Get the host from the URI. 990 $host = $uri->toString(['scheme', 'user', 'pass', 'host', 'port']); 991 992 // Check if the path includes "index.php". 993 if (strpos($path, 'index.php') !== false) 994 { 995 // Remove the index.php portion of the path. 996 $path = substr_replace($path, '', strpos($path, 'index.php'), 9); 997 } 998 999 $path = rtrim($path, '/\\'); 1000 1001 // Set the base URI both as just a path and as the full URI. 1002 $this->set('uri.base.full', $host . $path . '/'); 1003 $this->set('uri.base.host', $host); 1004 $this->set('uri.base.path', $path . '/'); 1005 1006 // Set the extended (non-base) part of the request URI as the route. 1007 if (stripos($this->get('uri.request'), $this->get('uri.base.full')) === 0) 1008 { 1009 $this->set('uri.route', substr_replace($this->get('uri.request'), '', 0, \strlen($this->get('uri.base.full')))); 1010 } 1011 1012 // Get an explicitly set media URI is present. 1013 $mediaURI = trim($this->get('media_uri')); 1014 1015 if ($mediaURI) 1016 { 1017 if (strpos($mediaURI, '://') !== false) 1018 { 1019 $this->set('uri.media.full', $mediaURI); 1020 $this->set('uri.media.path', $mediaURI); 1021 } 1022 else 1023 { 1024 // Normalise slashes. 1025 $mediaURI = trim($mediaURI, '/\\'); 1026 $mediaURI = !empty($mediaURI) ? '/' . $mediaURI . '/' : '/'; 1027 $this->set('uri.media.full', $this->get('uri.base.host') . $mediaURI); 1028 $this->set('uri.media.path', $mediaURI); 1029 } 1030 } 1031 else 1032 { 1033 // No explicit media URI was set, build it dynamically from the base uri. 1034 $this->set('uri.media.full', $this->get('uri.base.full') . 'media/'); 1035 $this->set('uri.media.path', $this->get('uri.base.path') . 'media/'); 1036 } 1037 } 1038 1039 /** 1040 * Tests whether a string contains only 7bit ASCII bytes. 1041 * 1042 * You might use this to conditionally check whether a string 1043 * needs handling as UTF-8 or not, potentially offering performance 1044 * benefits by using the native PHP equivalent if it's just ASCII e.g.; 1045 * 1046 * @param string $str The string to test. 1047 * 1048 * @return boolean True if the string is all ASCII 1049 * 1050 * @since 1.4.0 1051 */ 1052 public static function isAscii($str) 1053 { 1054 // Search for any bytes which are outside the ASCII range... 1055 return preg_match('/(?:[^\x00-\x7F])/', $str) !== 1; 1056 } 1057 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |