View source
<?php
namespace Zend\Diactoros;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\UploadedFileInterface;
use stdClass;
abstract class ServerRequestFactory {
private static $apacheRequestHeaders = 'apache_request_headers';
public static function fromGlobals(array $server = null, array $query = null, array $body = null, array $cookies = null, array $files = null) {
$server = static::normalizeServer($server ?: $_SERVER);
$files = static::normalizeFiles($files ?: $_FILES);
$headers = static::marshalHeaders($server);
$request = new ServerRequest($server, $files, static::marshalUriFromServer($server, $headers), static::get('REQUEST_METHOD', $server, 'GET'), 'php://input', $headers);
return $request
->withCookieParams($cookies ?: $_COOKIE)
->withQueryParams($query ?: $_GET)
->withParsedBody($body ?: $_POST);
}
public static function get($key, array $values, $default = null) {
if (array_key_exists($key, $values)) {
return $values[$key];
}
return $default;
}
public static function getHeader($header, array $headers, $default = null) {
$header = strtolower($header);
$headers = array_change_key_case($headers, CASE_LOWER);
if (array_key_exists($header, $headers)) {
$value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
return $value;
}
return $default;
}
public static function normalizeServer(array $server) {
$apacheRequestHeaders = self::$apacheRequestHeaders;
if (isset($server['HTTP_AUTHORIZATION']) || !is_callable($apacheRequestHeaders)) {
return $server;
}
$apacheRequestHeaders = $apacheRequestHeaders();
if (isset($apacheRequestHeaders['Authorization'])) {
$server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['Authorization'];
return $server;
}
if (isset($apacheRequestHeaders['authorization'])) {
$server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['authorization'];
return $server;
}
return $server;
}
public static function normalizeFiles(array $files) {
$normalized = [];
foreach ($files as $key => $value) {
if ($value instanceof UploadedFileInterface) {
$normalized[$key] = $value;
continue;
}
if (is_array($value) && isset($value['tmp_name'])) {
$normalized[$key] = self::createUploadedFileFromSpec($value);
continue;
}
if (is_array($value)) {
$normalized[$key] = self::normalizeFiles($value);
continue;
}
throw new InvalidArgumentException('Invalid value in files specification');
}
return $normalized;
}
public static function marshalHeaders(array $server) {
$headers = [];
foreach ($server as $key => $value) {
if (strpos($key, 'HTTP_COOKIE') === 0) {
continue;
}
if ($value && strpos($key, 'HTTP_') === 0) {
$name = strtr(substr($key, 5), '_', ' ');
$name = strtr(ucwords(strtolower($name)), ' ', '-');
$name = strtolower($name);
$headers[$name] = $value;
continue;
}
if ($value && strpos($key, 'CONTENT_') === 0) {
$name = substr($key, 8);
$name = 'Content-' . ($name == 'MD5' ? $name : ucfirst(strtolower($name)));
$name = strtolower($name);
$headers[$name] = $value;
continue;
}
}
return $headers;
}
public static function marshalUriFromServer(array $server, array $headers) {
$uri = new Uri('');
$scheme = 'http';
$https = self::get('HTTPS', $server);
if ($https && 'off' !== $https || self::getHeader('x-forwarded-proto', $headers, false) === 'https') {
$scheme = 'https';
}
if (!empty($scheme)) {
$uri = $uri
->withScheme($scheme);
}
$accumulator = (object) [
'host' => '',
'port' => null,
];
self::marshalHostAndPortFromHeaders($accumulator, $server, $headers);
$host = $accumulator->host;
$port = $accumulator->port;
if (!empty($host)) {
$uri = $uri
->withHost($host);
if (!empty($port)) {
$uri = $uri
->withPort($port);
}
}
$path = self::marshalRequestUri($server);
$path = self::stripQueryString($path);
$query = '';
if (isset($server['QUERY_STRING'])) {
$query = ltrim($server['QUERY_STRING'], '?');
}
return $uri
->withPath($path)
->withQuery($query);
}
public static function marshalHostAndPortFromHeaders(stdClass $accumulator, array $server, array $headers) {
if (self::getHeader('host', $headers, false)) {
self::marshalHostAndPortFromHeader($accumulator, self::getHeader('host', $headers));
return;
}
if (!isset($server['SERVER_NAME'])) {
return;
}
$accumulator->host = $server['SERVER_NAME'];
if (isset($server['SERVER_PORT'])) {
$accumulator->port = (int) $server['SERVER_PORT'];
}
if (!isset($server['SERVER_ADDR']) || !preg_match('/^\\[[0-9a-fA-F\\:]+\\]$/', $accumulator->host)) {
return;
}
self::marshalIpv6HostAndPort($accumulator, $server);
}
public static function marshalRequestUri(array $server) {
$iisUrlRewritten = self::get('IIS_WasUrlRewritten', $server);
$unencodedUrl = self::get('UNENCODED_URL', $server, '');
if ('1' == $iisUrlRewritten && !empty($unencodedUrl)) {
return $unencodedUrl;
}
$requestUri = self::get('REQUEST_URI', $server);
$httpXRewriteUrl = self::get('HTTP_X_REWRITE_URL', $server);
if ($httpXRewriteUrl !== null) {
$requestUri = $httpXRewriteUrl;
}
$httpXOriginalUrl = self::get('HTTP_X_ORIGINAL_URL', $server);
if ($httpXOriginalUrl !== null) {
$requestUri = $httpXOriginalUrl;
}
if ($requestUri !== null) {
return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
}
$origPathInfo = self::get('ORIG_PATH_INFO', $server);
if (empty($origPathInfo)) {
return '/';
}
return $origPathInfo;
}
public static function stripQueryString($path) {
if (($qpos = strpos($path, '?')) !== false) {
return substr($path, 0, $qpos);
}
return $path;
}
private static function marshalHostAndPortFromHeader(stdClass $accumulator, $host) {
if (is_array($host)) {
$host = implode(', ', $host);
}
$accumulator->host = $host;
$accumulator->port = null;
if (preg_match('|\\:(\\d+)$|', $accumulator->host, $matches)) {
$accumulator->host = substr($accumulator->host, 0, -1 * (strlen($matches[1]) + 1));
$accumulator->port = (int) $matches[1];
}
}
private static function marshalIpv6HostAndPort(stdClass $accumulator, array $server) {
$accumulator->host = '[' . $server['SERVER_ADDR'] . ']';
$accumulator->port = $accumulator->port ?: 80;
if ($accumulator->port . ']' === substr($accumulator->host, strrpos($accumulator->host, ':') + 1)) {
$accumulator->port = null;
}
}
private static function createUploadedFileFromSpec(array $value) {
if (is_array($value['tmp_name'])) {
return self::normalizeNestedFileSpec($value);
}
return new UploadedFile($value['tmp_name'], $value['size'], $value['error'], $value['name'], $value['type']);
}
private static function normalizeNestedFileSpec(array $files = []) {
$normalizedFiles = [];
foreach (array_keys($files['tmp_name']) as $key) {
$spec = [
'tmp_name' => $files['tmp_name'][$key],
'size' => $files['size'][$key],
'error' => $files['error'][$key],
'name' => $files['name'][$key],
'type' => $files['type'][$key],
];
$normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
}
return $normalizedFiles;
}
}