Skip to content

Commit c109108

Browse files
committed
add a http factory implement class
1 parent 8c9e8ce commit c109108

File tree

1 file changed

+340
-0
lines changed

1 file changed

+340
-0
lines changed

src/HttpFactory.php

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: inhere
5+
* Date: 2017-10-20
6+
* Time: 13:20
7+
*/
8+
9+
namespace Inhere\Http;
10+
11+
use Inhere\Library\Collections\CollectionInterface;
12+
use Inhere\Library\Collections\SimpleCollection;
13+
use Psr\Http\Message\RequestInterface;
14+
use Psr\Http\Message\ResponseInterface;
15+
use Psr\Http\Message\ServerRequestInterface;
16+
use Psr\Http\Message\StreamInterface;
17+
use Psr\Http\Message\UploadedFileInterface;
18+
use Psr\Http\Message\UriInterface;
19+
20+
/**
21+
* Class HttpFactory
22+
* @package Inhere\Http
23+
* @link https://github.com/php-fig/fig-standards/blob/master/proposed/http-factory/http-factory.md
24+
*/
25+
class HttpFactory
26+
{
27+
/**
28+
* Special HTTP headers that do not have the "HTTP_" prefix
29+
* @var array
30+
*/
31+
protected static $special = [
32+
'CONTENT_TYPE' => 1,
33+
'CONTENT_LENGTH' => 1,
34+
'PHP_AUTH_USER' => 1,
35+
'PHP_AUTH_PW' => 1,
36+
'PHP_AUTH_DIGEST' => 1,
37+
'AUTH_TYPE' => 1,
38+
];
39+
40+
/**
41+
* RequestFactoryInterface
42+
*/
43+
44+
/**
45+
* Create a new request.
46+
* @param string $method
47+
* @param UriInterface|string $uri
48+
* @return RequestInterface
49+
*/
50+
public static function createRequest($method, $uri)
51+
{
52+
return new Request($method, $uri);
53+
}
54+
55+
/**
56+
* ResponseFactoryInterface
57+
*/
58+
59+
/**
60+
* Create a new response.
61+
* @param integer $code HTTP status code
62+
* @return ResponseInterface
63+
*/
64+
public static function createResponse($code = 200)
65+
{
66+
return new Response($code);
67+
}
68+
69+
/**
70+
* ServerRequestFactoryInterface
71+
*/
72+
73+
/**
74+
* Create a new server request.
75+
* @param string $method
76+
* @param UriInterface|string $uri
77+
* @return ServerRequestInterface
78+
*/
79+
public static function createServerRequest($method, $uri)
80+
{
81+
return new Request($method, $uri);
82+
}
83+
84+
/**
85+
* Create a new server request from server variables.
86+
* @param array $server Typically $_SERVER or similar structure.
87+
* @return ServerRequestInterface
88+
* @throws \InvalidArgumentException
89+
* If no valid method or URI can be determined.
90+
*/
91+
public static function createServerRequestFromArray(array $server)
92+
{
93+
$env = new SimpleCollection($server);
94+
$method = $env['REQUEST_METHOD'];
95+
$uri = static::createUriFromArray($env);
96+
$headers = static::createHeadersFromArray($env);
97+
$cookies = Cookies::parseFromRawHeader($headers->get('Cookie', []));
98+
$serverParams = $env->all();
99+
$body = new RequestBody();
100+
$uploadedFiles = UploadedFile::createFromFILES();
101+
102+
$request = new Request($method, $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);
103+
104+
if ($method === 'POST' &&
105+
in_array($request->getMediaType(), ['application/x-www-form-urlencoded', 'multipart/form-data'], true)
106+
) {
107+
// parsed body must be $_POST
108+
$request = $request->withParsedBody($_POST);
109+
}
110+
111+
return $request;
112+
}
113+
114+
/**
115+
* StreamFactoryInterface
116+
*/
117+
118+
/**
119+
* Create a new stream from a string.
120+
* The stream SHOULD be created with a temporary resource.
121+
* @param string $content
122+
* @return StreamInterface
123+
*/
124+
public static function createStream($content = '')
125+
{
126+
return new RequestBody($content);
127+
}
128+
129+
/**
130+
* Create a stream from an existing file.
131+
* The file MUST be opened using the given mode, which may be any mode
132+
* supported by the `fopen` function.
133+
* The `$filename` MAY be any string supported by `fopen()`.
134+
* @param string $filename
135+
* @param string $mode
136+
* @return StreamInterface
137+
*/
138+
public static function createStreamFromFile($filename, $mode = 'r')
139+
{
140+
// $stream = fopen('php://temp', $mode);
141+
$stream = fopen($filename, $mode);
142+
143+
return new Body($stream);
144+
}
145+
146+
/**
147+
* Create a new stream from an existing resource.
148+
* The stream MUST be readable and may be writable.
149+
* @param resource $resource e.g `$resource = fopen('php://temp', 'r+');`
150+
* @return StreamInterface
151+
*/
152+
public static function createStreamFromResource($resource)
153+
{
154+
return new Body($resource);
155+
}
156+
157+
/**
158+
* UploadedFileFactoryInterface
159+
*/
160+
161+
/**
162+
* Create a new uploaded file.
163+
* If a string is used to create the file, a temporary resource will be
164+
* created with the content of the string.
165+
* If a size is not provided it will be determined by checking the size of
166+
* the file.
167+
* @see http://php.net/manual/features.file-upload.post-method.php
168+
* @see http://php.net/manual/features.file-upload.errors.php
169+
* @param string|resource $file
170+
* @param integer $size in bytes
171+
* @param integer $error PHP file upload error
172+
* @param string $clientFilename
173+
* @param string $clientMediaType
174+
* @return UploadedFileInterface
175+
* @throws \InvalidArgumentException If the file resource is not readable.
176+
*/
177+
public static function createUploadedFile(
178+
$file, $size = null, $error = \UPLOAD_ERR_OK,
179+
$clientFilename = null, $clientMediaType = null
180+
)
181+
{
182+
return new UploadedFile($file, $clientFilename, $clientMediaType, $size, $error);
183+
}
184+
185+
/**
186+
* UriFactoryInterface
187+
*/
188+
189+
/**
190+
* Create a new URI.
191+
* @param string $uri
192+
* @return UriInterface
193+
* @throws \InvalidArgumentException If the given URI cannot be parsed.
194+
*/
195+
public function createUri($uri = '')
196+
{
197+
return Uri::createFromString($uri);
198+
}
199+
200+
/*******************************************************************************
201+
* extended factory methods
202+
******************************************************************************/
203+
204+
/**
205+
* @param CollectionInterface|array $env
206+
* @return Headers
207+
*/
208+
public static function createHeadersFromArray($env)
209+
{
210+
$data = [];
211+
$env = self::ensureIsCollection($env);
212+
$env = self::determineAuthorization($env);
213+
214+
foreach ($env as $key => $value) {
215+
$key = strtoupper($key);
216+
if (isset(static::$special[$key]) || strpos($key, 'HTTP_') === 0) {
217+
if ($key !== 'HTTP_CONTENT_LENGTH') {
218+
$data[$key] = $value;
219+
}
220+
}
221+
}
222+
223+
return new Headers($data);
224+
}
225+
226+
/**
227+
* If HTTP_AUTHORIZATION does not exist tries to get it from
228+
* getallheaders() when available.
229+
* @param CollectionInterface $env The Slim application SimpleCollection
230+
* @return CollectionInterface
231+
*/
232+
public static function determineAuthorization($env)
233+
{
234+
$authorization = $env->get('HTTP_AUTHORIZATION');
235+
236+
if (null === $authorization && is_callable('getallheaders')) {
237+
$headers = getallheaders();
238+
$headers = array_change_key_case($headers, CASE_LOWER);
239+
if (isset($headers['authorization'])) {
240+
$env->set('HTTP_AUTHORIZATION', $headers['authorization']);
241+
}
242+
}
243+
244+
return $env;
245+
}
246+
247+
/**
248+
* @param CollectionInterface|array $env
249+
* @return Uri
250+
*/
251+
public static function createUriFromArray($env)
252+
{
253+
$env = self::ensureIsCollection($env);
254+
255+
// Scheme
256+
$isSecure = $env->get('HTTPS');
257+
$scheme = (empty($isSecure) || $isSecure === 'off') ? 'http' : 'https';
258+
259+
// Authority: Username and password
260+
$username = $env->get('PHP_AUTH_USER', '');
261+
$password = $env->get('PHP_AUTH_PW', '');
262+
263+
// Authority: Host
264+
if ($env->has('HTTP_HOST')) {
265+
$host = $env->get('HTTP_HOST');
266+
} else {
267+
$host = $env->get('SERVER_NAME');
268+
}
269+
270+
// Authority: Port
271+
$port = (int)$env->get('SERVER_PORT', 80);
272+
if (preg_match('/^(\[[a-fA-F0-9:.]+\])(:\d+)?\z/', $host, $matches)) {
273+
$host = $matches[1];
274+
275+
if ($matches[2]) {
276+
$port = (int)substr($matches[2], 1);
277+
}
278+
} else {
279+
$pos = strpos($host, ':');
280+
if ($pos !== false) {
281+
$port = (int)substr($host, $pos + 1);
282+
$host = strstr($host, ':', true);
283+
}
284+
}
285+
286+
// Path
287+
$requestScriptName = parse_url($env->get('SCRIPT_NAME'), PHP_URL_PATH);
288+
$requestScriptDir = dirname($requestScriptName);
289+
290+
// parse_url() requires a full URL. As we don't extract the domain name or scheme,
291+
// we use a stand-in.
292+
$requestUri = parse_url('http://example.com' . $env->get('REQUEST_URI'), PHP_URL_PATH);
293+
294+
$basePath = '';
295+
$virtualPath = $requestUri;
296+
if (stripos($requestUri, $requestScriptName) === 0) {
297+
$basePath = $requestScriptName;
298+
} elseif ($requestScriptDir !== '/' && stripos($requestUri, $requestScriptDir) === 0) {
299+
$basePath = $requestScriptDir;
300+
}
301+
302+
if ($basePath) {
303+
$virtualPath = ltrim(substr($requestUri, strlen($basePath)), '/');
304+
}
305+
306+
// Query string
307+
$queryString = $env->get('QUERY_STRING', '');
308+
if ($queryString === '') {
309+
$queryString = parse_url('http://example.com' . $env->get('REQUEST_URI'), PHP_URL_QUERY);
310+
}
311+
312+
// Fragment
313+
$fragment = '';
314+
315+
// Build Uri
316+
$uri = new Uri($scheme, $host, $port, $virtualPath, $queryString, $fragment, $username, $password);
317+
if ($basePath) {
318+
$uri = $uri->withBasePath($basePath);
319+
}
320+
321+
return $uri;
322+
}
323+
324+
/**
325+
* @param $data
326+
* @return CollectionInterface
327+
*/
328+
public static function ensureIsCollection($data)
329+
{
330+
if (is_array($data)) {
331+
return new SimpleCollection($data);
332+
}
333+
334+
if ($data instanceof CollectionInterface) {
335+
return $data;
336+
}
337+
338+
return new SimpleCollection((array)$data);
339+
}
340+
}

0 commit comments

Comments
 (0)