File indexing completed on 2025-01-26 05:29:13

0001 <?php
0002 
0003 namespace GuzzleHttp\Psr7;
0004 
0005 use InvalidArgumentException;
0006 use Psr\Http\Message\ServerRequestInterface;
0007 use Psr\Http\Message\UriInterface;
0008 use Psr\Http\Message\StreamInterface;
0009 use Psr\Http\Message\UploadedFileInterface;
0010 
0011 /**
0012  * Server-side HTTP request
0013  *
0014  * Extends the Request definition to add methods for accessing incoming data,
0015  * specifically server parameters, cookies, matched path parameters, query
0016  * string arguments, body parameters, and upload file information.
0017  *
0018  * "Attributes" are discovered via decomposing the request (and usually
0019  * specifically the URI path), and typically will be injected by the application.
0020  *
0021  * Requests are considered immutable; all methods that might change state are
0022  * implemented such that they retain the internal state of the current
0023  * message and return a new instance that contains the changed state.
0024  */
0025 class ServerRequest extends Request implements ServerRequestInterface
0026 {
0027     /**
0028      * @var array
0029      */
0030     private $attributes = [];
0031 
0032     /**
0033      * @var array
0034      */
0035     private $cookieParams = [];
0036 
0037     /**
0038      * @var null|array|object
0039      */
0040     private $parsedBody;
0041 
0042     /**
0043      * @var array
0044      */
0045     private $queryParams = [];
0046 
0047     /**
0048      * @var array
0049      */
0050     private $serverParams;
0051 
0052     /**
0053      * @var array
0054      */
0055     private $uploadedFiles = [];
0056 
0057     /**
0058      * @param string                               $method       HTTP method
0059      * @param string|UriInterface                  $uri          URI
0060      * @param array                                $headers      Request headers
0061      * @param string|null|resource|StreamInterface $body         Request body
0062      * @param string                               $version      Protocol version
0063      * @param array                                $serverParams Typically the $_SERVER superglobal
0064      */
0065     public function __construct(
0066         $method,
0067         $uri,
0068         array $headers = [],
0069         $body = null,
0070         $version = '1.1',
0071         array $serverParams = []
0072     ) {
0073         $this->serverParams = $serverParams;
0074 
0075         parent::__construct($method, $uri, $headers, $body, $version);
0076     }
0077 
0078     /**
0079      * Return an UploadedFile instance array.
0080      *
0081      * @param array $files A array which respect $_FILES structure
0082      * @throws InvalidArgumentException for unrecognized values
0083      * @return array
0084      */
0085     public static function normalizeFiles(array $files)
0086     {
0087         $normalized = [];
0088 
0089         foreach ($files as $key => $value) {
0090             if ($value instanceof UploadedFileInterface) {
0091                 $normalized[$key] = $value;
0092             } elseif (is_array($value) && isset($value['tmp_name'])) {
0093                 $normalized[$key] = self::createUploadedFileFromSpec($value);
0094             } elseif (is_array($value)) {
0095                 $normalized[$key] = self::normalizeFiles($value);
0096                 continue;
0097             } else {
0098                 throw new InvalidArgumentException('Invalid value in files specification');
0099             }
0100         }
0101 
0102         return $normalized;
0103     }
0104 
0105     /**
0106      * Create and return an UploadedFile instance from a $_FILES specification.
0107      *
0108      * If the specification represents an array of values, this method will
0109      * delegate to normalizeNestedFileSpec() and return that return value.
0110      *
0111      * @param array $value $_FILES struct
0112      * @return array|UploadedFileInterface
0113      */
0114     private static function createUploadedFileFromSpec(array $value)
0115     {
0116         if (is_array($value['tmp_name'])) {
0117             return self::normalizeNestedFileSpec($value);
0118         }
0119 
0120         return new UploadedFile(
0121             $value['tmp_name'],
0122             (int) $value['size'],
0123             (int) $value['error'],
0124             $value['name'],
0125             $value['type']
0126         );
0127     }
0128 
0129     /**
0130      * Normalize an array of file specifications.
0131      *
0132      * Loops through all nested files and returns a normalized array of
0133      * UploadedFileInterface instances.
0134      *
0135      * @param array $files
0136      * @return UploadedFileInterface[]
0137      */
0138     private static function normalizeNestedFileSpec(array $files = [])
0139     {
0140         $normalizedFiles = [];
0141 
0142         foreach (array_keys($files['tmp_name']) as $key) {
0143             $spec = [
0144                 'tmp_name' => $files['tmp_name'][$key],
0145                 'size'     => $files['size'][$key],
0146                 'error'    => $files['error'][$key],
0147                 'name'     => $files['name'][$key],
0148                 'type'     => $files['type'][$key],
0149             ];
0150             $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
0151         }
0152 
0153         return $normalizedFiles;
0154     }
0155 
0156     /**
0157      * Return a ServerRequest populated with superglobals:
0158      * $_GET
0159      * $_POST
0160      * $_COOKIE
0161      * $_FILES
0162      * $_SERVER
0163      *
0164      * @return ServerRequestInterface
0165      */
0166     public static function fromGlobals()
0167     {
0168         $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
0169         $headers = function_exists('getallheaders') ? getallheaders() : [];
0170         $uri = self::getUriFromGlobals();
0171         $body = new LazyOpenStream('php://input', 'r+');
0172         $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
0173 
0174         $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
0175 
0176         return $serverRequest
0177             ->withCookieParams($_COOKIE)
0178             ->withQueryParams($_GET)
0179             ->withParsedBody($_POST)
0180             ->withUploadedFiles(self::normalizeFiles($_FILES));
0181     }
0182 
0183     /**
0184      * Get a Uri populated with values from $_SERVER.
0185      *
0186      * @return UriInterface
0187      */
0188     public static function getUriFromGlobals() {
0189         $uri = new Uri('');
0190 
0191         $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
0192 
0193         $hasPort = false;
0194         if (isset($_SERVER['HTTP_HOST'])) {
0195             $hostHeaderParts = explode(':', $_SERVER['HTTP_HOST']);
0196             $uri = $uri->withHost($hostHeaderParts[0]);
0197             if (isset($hostHeaderParts[1])) {
0198                 $hasPort = true;
0199                 $uri = $uri->withPort($hostHeaderParts[1]);
0200             }
0201         } elseif (isset($_SERVER['SERVER_NAME'])) {
0202             $uri = $uri->withHost($_SERVER['SERVER_NAME']);
0203         } elseif (isset($_SERVER['SERVER_ADDR'])) {
0204             $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
0205         }
0206 
0207         if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
0208             $uri = $uri->withPort($_SERVER['SERVER_PORT']);
0209         }
0210 
0211         $hasQuery = false;
0212         if (isset($_SERVER['REQUEST_URI'])) {
0213             $requestUriParts = explode('?', $_SERVER['REQUEST_URI']);
0214             $uri = $uri->withPath($requestUriParts[0]);
0215             if (isset($requestUriParts[1])) {
0216                 $hasQuery = true;
0217                 $uri = $uri->withQuery($requestUriParts[1]);
0218             }
0219         }
0220 
0221         if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
0222             $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
0223         }
0224 
0225         return $uri;
0226     }
0227 
0228 
0229     /**
0230      * {@inheritdoc}
0231      */
0232     public function getServerParams()
0233     {
0234         return $this->serverParams;
0235     }
0236 
0237     /**
0238      * {@inheritdoc}
0239      */
0240     public function getUploadedFiles()
0241     {
0242         return $this->uploadedFiles;
0243     }
0244 
0245     /**
0246      * {@inheritdoc}
0247      */
0248     public function withUploadedFiles(array $uploadedFiles)
0249     {
0250         $new = clone $this;
0251         $new->uploadedFiles = $uploadedFiles;
0252 
0253         return $new;
0254     }
0255 
0256     /**
0257      * {@inheritdoc}
0258      */
0259     public function getCookieParams()
0260     {
0261         return $this->cookieParams;
0262     }
0263 
0264     /**
0265      * {@inheritdoc}
0266      */
0267     public function withCookieParams(array $cookies)
0268     {
0269         $new = clone $this;
0270         $new->cookieParams = $cookies;
0271 
0272         return $new;
0273     }
0274 
0275     /**
0276      * {@inheritdoc}
0277      */
0278     public function getQueryParams()
0279     {
0280         return $this->queryParams;
0281     }
0282 
0283     /**
0284      * {@inheritdoc}
0285      */
0286     public function withQueryParams(array $query)
0287     {
0288         $new = clone $this;
0289         $new->queryParams = $query;
0290 
0291         return $new;
0292     }
0293 
0294     /**
0295      * {@inheritdoc}
0296      */
0297     public function getParsedBody()
0298     {
0299         return $this->parsedBody;
0300     }
0301 
0302     /**
0303      * {@inheritdoc}
0304      */
0305     public function withParsedBody($data)
0306     {
0307         $new = clone $this;
0308         $new->parsedBody = $data;
0309 
0310         return $new;
0311     }
0312 
0313     /**
0314      * {@inheritdoc}
0315      */
0316     public function getAttributes()
0317     {
0318         return $this->attributes;
0319     }
0320 
0321     /**
0322      * {@inheritdoc}
0323      */
0324     public function getAttribute($attribute, $default = null)
0325     {
0326         if (false === array_key_exists($attribute, $this->attributes)) {
0327             return $default;
0328         }
0329 
0330         return $this->attributes[$attribute];
0331     }
0332 
0333     /**
0334      * {@inheritdoc}
0335      */
0336     public function withAttribute($attribute, $value)
0337     {
0338         $new = clone $this;
0339         $new->attributes[$attribute] = $value;
0340 
0341         return $new;
0342     }
0343 
0344     /**
0345      * {@inheritdoc}
0346      */
0347     public function withoutAttribute($attribute)
0348     {
0349         if (false === array_key_exists($attribute, $this->attributes)) {
0350             return $this;
0351         }
0352 
0353         $new = clone $this;
0354         unset($new->attributes[$attribute]);
0355 
0356         return $new;
0357     }
0358 }