Response.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. declare(strict_types=1);
  3. namespace GuzzleHttp\Psr7;
  4. use Psr\Http\Message\ResponseInterface;
  5. use Psr\Http\Message\StreamInterface;
  6. /**
  7. * PSR-7 response implementation.
  8. */
  9. class Response implements ResponseInterface
  10. {
  11. use MessageTrait;
  12. /** Map of standard HTTP status code/reason phrases */
  13. private const PHRASES = [
  14. 100 => 'Continue',
  15. 101 => 'Switching Protocols',
  16. 102 => 'Processing',
  17. 200 => 'OK',
  18. 201 => 'Created',
  19. 202 => 'Accepted',
  20. 203 => 'Non-Authoritative Information',
  21. 204 => 'No Content',
  22. 205 => 'Reset Content',
  23. 206 => 'Partial Content',
  24. 207 => 'Multi-status',
  25. 208 => 'Already Reported',
  26. 300 => 'Multiple Choices',
  27. 301 => 'Moved Permanently',
  28. 302 => 'Found',
  29. 303 => 'See Other',
  30. 304 => 'Not Modified',
  31. 305 => 'Use Proxy',
  32. 306 => 'Switch Proxy',
  33. 307 => 'Temporary Redirect',
  34. 308 => 'Permanent Redirect',
  35. 400 => 'Bad Request',
  36. 401 => 'Unauthorized',
  37. 402 => 'Payment Required',
  38. 403 => 'Forbidden',
  39. 404 => 'Not Found',
  40. 405 => 'Method Not Allowed',
  41. 406 => 'Not Acceptable',
  42. 407 => 'Proxy Authentication Required',
  43. 408 => 'Request Time-out',
  44. 409 => 'Conflict',
  45. 410 => 'Gone',
  46. 411 => 'Length Required',
  47. 412 => 'Precondition Failed',
  48. 413 => 'Request Entity Too Large',
  49. 414 => 'Request-URI Too Large',
  50. 415 => 'Unsupported Media Type',
  51. 416 => 'Requested range not satisfiable',
  52. 417 => 'Expectation Failed',
  53. 418 => 'I\'m a teapot',
  54. 422 => 'Unprocessable Entity',
  55. 423 => 'Locked',
  56. 424 => 'Failed Dependency',
  57. 425 => 'Unordered Collection',
  58. 426 => 'Upgrade Required',
  59. 428 => 'Precondition Required',
  60. 429 => 'Too Many Requests',
  61. 431 => 'Request Header Fields Too Large',
  62. 451 => 'Unavailable For Legal Reasons',
  63. 500 => 'Internal Server Error',
  64. 501 => 'Not Implemented',
  65. 502 => 'Bad Gateway',
  66. 503 => 'Service Unavailable',
  67. 504 => 'Gateway Time-out',
  68. 505 => 'HTTP Version not supported',
  69. 506 => 'Variant Also Negotiates',
  70. 507 => 'Insufficient Storage',
  71. 508 => 'Loop Detected',
  72. 510 => 'Not Extended',
  73. 511 => 'Network Authentication Required',
  74. ];
  75. /** @var string */
  76. private $reasonPhrase;
  77. /** @var int */
  78. private $statusCode;
  79. /**
  80. * @param int $status Status code
  81. * @param array<string, string|string[]> $headers Response headers
  82. * @param string|resource|StreamInterface|null $body Response body
  83. * @param string $version Protocol version
  84. * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
  85. */
  86. public function __construct(
  87. int $status = 200,
  88. array $headers = [],
  89. $body = null,
  90. string $version = '1.1',
  91. string $reason = null
  92. ) {
  93. $this->assertStatusCodeRange($status);
  94. $this->statusCode = $status;
  95. if ($body !== '' && $body !== null) {
  96. $this->stream = Utils::streamFor($body);
  97. }
  98. $this->setHeaders($headers);
  99. if ($reason == '' && isset(self::PHRASES[$this->statusCode])) {
  100. $this->reasonPhrase = self::PHRASES[$this->statusCode];
  101. } else {
  102. $this->reasonPhrase = (string) $reason;
  103. }
  104. $this->protocol = $version;
  105. }
  106. public function getStatusCode(): int
  107. {
  108. return $this->statusCode;
  109. }
  110. public function getReasonPhrase(): string
  111. {
  112. return $this->reasonPhrase;
  113. }
  114. public function withStatus($code, $reasonPhrase = ''): ResponseInterface
  115. {
  116. $this->assertStatusCodeIsInteger($code);
  117. $code = (int) $code;
  118. $this->assertStatusCodeRange($code);
  119. $new = clone $this;
  120. $new->statusCode = $code;
  121. if ($reasonPhrase == '' && isset(self::PHRASES[$new->statusCode])) {
  122. $reasonPhrase = self::PHRASES[$new->statusCode];
  123. }
  124. $new->reasonPhrase = (string) $reasonPhrase;
  125. return $new;
  126. }
  127. /**
  128. * @param mixed $statusCode
  129. */
  130. private function assertStatusCodeIsInteger($statusCode): void
  131. {
  132. if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
  133. throw new \InvalidArgumentException('Status code must be an integer value.');
  134. }
  135. }
  136. private function assertStatusCodeRange(int $statusCode): void
  137. {
  138. if ($statusCode < 100 || $statusCode >= 600) {
  139. throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
  140. }
  141. }
  142. }