Completed
Push — master ( 61475a...8376f2 )
by Nazar
04:08
created

Psr7::from_psr7_query()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * @package   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\Request;
9
use
10
	Exception,
11
	cs\ExitException;
12
13
trait Psr7 {
14
	/**
15
	 * Initialize request from PSR-7 request object
16
	 *
17
	 * @param \Psr\Http\Message\ServerRequestInterface $request
18
	 *
19
	 * @throws \cs\ExitException
20
	 */
21
	function from_psr7 ($request) {
22
		$this->from_psr7_server($request);
23
		$this->from_psr7_query($request);
24
		$this->from_psr7_data_and_files($request);
25
		$this->init_route();
26
	}
27
	/**
28
	 * @param \Psr\Http\Message\ServerRequestInterface $request
29
	 */
30
	protected function from_psr7_server ($request) {
31
		$uri          = $request->getUri();
32
		$this->method = $request->getMethod();
33
		$this->host   = $uri->getHost();
34
		$this->scheme = $uri->getScheme();
35
		$this->secure = $this->scheme == 'https';
36
		if (
37
			(!$this->secure && $uri->getPort() != 80) ||
38
			($this->secure && $uri->getPort() != 443)
39
		) {
40
			$this->host .= ':'.$uri->getPort();
41
		}
42
		$this->protocol     = 'HTTP/'.$request->getProtocolVersion();
43
		$this->path         = $uri->getPath();
44
		$this->query_string = $uri->getQuery();
45
		/** @noinspection NestedTernaryOperatorInspection */
46
		$this->uri         = $this->path.($this->query_string ? "?$this->query_string" : '') ?: '/';
47
		$this->remote_addr = @$request->getServerParams()['REMOTE_ADDR'] ?: '127.0.0.1';
48
		$this->ip          = $this->ip(
49
			[
50
				'HTTP_X_FORWARDED_FOR'     => $request->getHeaderLine('x-forwarded-for'),
51
				'HTTP_CLIENT_IP'           => $request->getHeaderLine('client-ip'),
52
				'HTTP_X_FORWARDED'         => $request->getHeaderLine('x-forwarded'),
53
				'HTTP_X_CLUSTER_CLIENT_IP' => $request->getHeaderLine('x-cluster-client-ip'),
54
				'HTTP_FORWARDED_FOR'       => $request->getHeaderLine('forwarded-for'),
55
				'HTTP_FORWARDED'           => $request->getHeaderLine('forwarded')
56
			]
57
		);
58
	}
59
	/**
60
	 * @param \Psr\Http\Message\ServerRequestInterface $request
61
	 */
62
	protected function from_psr7_query ($request) {
63
		$this->query = $request->getQueryParams();
64
	}
65
	/**
66
	 * @todo Implement custom stream wrapper for files and data in general in order to avoid data duplication
67
	 *
68
	 * @param \Psr\Http\Message\ServerRequestInterface $request
69
	 *
70
	 * @throws ExitException
71
	 */
72
	protected function from_psr7_data_and_files ($request) {
73
		$data         = [];
74
		$data_stream  = null;
75
		$content_type = $this->header('content-type');
76
		$body_stream  = $request->getBody();
77
		if (preg_match('#^application/([^+\s]+\+)?json#', $content_type)) {
78
			$data = _json_decode((string)$body_stream) ?: [];
79
		} elseif (strpos($content_type, 'application/x-www-form-urlencoded') === 0) {
80
			@parse_str((string)$body_stream, $data);
81
		} else {
82
			try {
83
				$position = $body_stream->tell();
84
				$body_stream->rewind();
85
				$data_stream = fopen('php://temp', 'w+b');
86
				while (!$body_stream->eof()) {
87
					fwrite($data_stream, $body_stream->read(1024));
88
				}
89
				$body_stream->seek($position);
90
			} catch (Exception $e) {
91
				// Do nothing
92
			}
93
		}
94
		$this->init_data_and_files(
1 ignored issue
show
Bug introduced by
It seems like init_data_and_files() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
95
			$data,
96
			$this->from_psr7_files_internal(
97
				$request->getUploadedFiles()
98
			),
99
			$data_stream
100
		);
101
	}
102
	/**
103
	 * @param array|\Psr\Http\Message\UploadedFileInterface $files
104
	 *
105
	 * @return array|\Psr\Http\Message\UploadedFileInterface
106
	 */
107
	protected function from_psr7_files_internal ($files) {
108
		if (is_array($files)) {
109
			foreach ($files as $field => &$file) {
110
				$file = $this->from_psr7_files_internal($file);
111
				if (!$file) {
112
					unset($files[$field]);
113
				}
114
			}
115
			return $files;
116
		}
117
		try {
118
			$source_file_stream = $files->getStream();
119
			$position           = $source_file_stream->tell();
120
			$source_file_stream->rewind();
121
			$file_stream = fopen('php://temp', 'w+b');
122
			while (!$source_file_stream->eof()) {
123
				fwrite($file_stream, $source_file_stream->read(1024));
124
			}
125
			$source_file_stream->seek($position);
126
		} catch (Exception $e) {
127
			return [];
128
		}
129
		return [
130
			'name'   => $files->getClientFilename(),
131
			'type'   => $files->getClientMediaType(),
132
			'size'   => $files->getSize(),
133
			'stream' => $file_stream,
134
			'error'  => $files->getError()
135
		];
136
	}
137
}
138