Completed
Push — master ( 0420f0...2a581f )
by smiley
01:40
created

message_helpers.php ➔ get_json()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @filesource   message_helpers.php
4
 * @created      28.08.2018
5
 * @author       smiley <[email protected]>
6
 * @copyright    2018 smiley
7
 * @license      MIT
8
 */
9
10
namespace chillerlan\HTTP\Psr7;
11
12
use InvalidArgumentException;
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\UploadedFileInterface;
15
16
const PSR7_INCLUDES = true;
17
18
/**
19
 * Normalizes an array of header lines to format "Name: Value"
20
 *
21
 * @param array $headers
22
 *
23
 * @return array
24
 */
25
function normalize_request_headers(array $headers):array{
26
	$normalized_headers = [];
27
28
	foreach($headers as $key => $val){
29
30
		if(is_numeric($key)){
31
32
			if(is_string($val)){
33
				$header = explode(':', $val, 2);
34
35
				if(count($header) !== 2){
36
					continue;
37
				}
38
39
				$key = $header[0];
40
				$val = $header[1];
41
			}
42
			elseif(is_array($val)){
43
				$key = array_keys($val)[0];
44
				$val = array_values($val)[0];
45
			}
46
			else{
47
				continue;
48
			}
49
		}
50
51
		$key = strtolower(trim($key));
52
53
		$normalized_headers[$key] = trim($val);
54
	}
55
56
	return $normalized_headers;
57
}
58
59
/**
60
 * @param mixed $data
61
 *
62
 * @return mixed
63
 */
64
function raw_urlencode($data){
65
66
	if(is_array($data)){
67
		return array_map(__NAMESPACE__.'\\raw_urlencode', $data);
68
	}
69
70
	return rawurlencode($data);
71
}
72
73
/**
74
 * from https://github.com/abraham/twitteroauth/blob/master/src/Util.php
75
 *
76
 * @param array  $params
77
 * @param bool   $urlencode
78
 * @param string $delimiter
79
 * @param string $enclosure
80
 *
81
 * @return string
82
 */
83
function build_http_query(array $params, bool $urlencode = null, string $delimiter = null, string $enclosure = null):string{
84
85
	if(empty($params)){
86
		return '';
87
	}
88
89
	// urlencode both keys and values
90
	if($urlencode ?? true){
91
		$params = array_combine(
92
			raw_urlencode(array_keys($params)),
93
			raw_urlencode(array_values($params))
94
		);
95
	}
96
97
	// Parameters are sorted by name, using lexicographical byte value ordering.
98
	// Ref: Spec: 9.1.1 (1)
99
	uksort($params, 'strcmp');
100
101
	$pairs     = [];
102
	$enclosure = $enclosure ?? '';
103
104
	foreach($params as $parameter => $value){
105
106
		if(is_array($value)){
107
			// If two or more parameters share the same name, they are sorted by their value
108
			// Ref: Spec: 9.1.1 (1)
109
			// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
110
			sort($value, SORT_STRING);
111
112
			foreach($value as $duplicateValue){
113
				$pairs[] = $parameter.'='.$enclosure.$duplicateValue.$enclosure;
114
			}
115
116
		}
117
		else{
118
			$pairs[] = $parameter.'='.$enclosure.$value.$enclosure;
119
		}
120
121
	}
122
123
	// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
124
	// Each name-value pair is separated by an '&' character (ASCII code 38)
125
	return implode($delimiter ?? '&', $pairs);
126
}
127
128
const BOOLEANS_AS_BOOL = 0;
129
const BOOLEANS_AS_INT = 1;
130
const BOOLEANS_AS_STRING = 2;
131
const BOOLEANS_AS_INT_STRING = 3;
132
/**
133
 * @param iterable  $params
134
 * @param int|null  $bool_cast converts booleans to a type determined like following:
135
 *                             BOOLEANS_AS_BOOL      : unchanged boolean value (default)
136
 *                             BOOLEANS_AS_INT       : integer values 0 or 1
137
 *                             BOOLEANS_AS_STRING    : "true"/"false" strings
138
 *                             BOOLEANS_AS_INT_STRING: "0"/"1"
139
 *
140
 * @param bool|null $remove_empty remove empty and NULL values
141
 *
142
 * @return array
143
 */
144
function clean_query_params(iterable $params, int $bool_cast = null, bool $remove_empty = null):array{
145
	$p = [];
146
	$bool_cast = $bool_cast ?? BOOLEANS_AS_BOOL;
147
	$remove_empty = $remove_empty ?? true;
148
149
	foreach($params as $key => $value){
150
151
		if(is_bool($value)){
152
153
			if($bool_cast === BOOLEANS_AS_BOOL){
154
				$p[$key] = $value;
155
			}
156
			elseif($bool_cast === BOOLEANS_AS_INT){
157
				$p[$key] = (int)$value;
158
			}
159
			elseif($bool_cast === BOOLEANS_AS_STRING){
160
				$p[$key] = $value ? 'true' : 'false';
161
			}
162
			elseif($bool_cast === BOOLEANS_AS_INT_STRING){
163
				$p[$key] = (string)(int)$value;
164
			}
165
166
		}
167
		elseif($remove_empty === true && ($value === null || (!is_numeric($value) && empty($value)))){
168
			continue;
169
		}
170
		else{
171
			$p[$key] = $value;
172
		}
173
	}
174
175
	return $p;
176
}
177
178
/**
179
 * merges additional query parameters into an existing query string
180
 *
181
 * @param string $uri
182
 * @param array  $query
183
 *
184
 * @return string
185
 */
186
function merge_query(string $uri, array $query):string{
187
	parse_str(parse_url($uri, PHP_URL_QUERY), $parsedquery);
188
189
	$requestURI = explode('?', $uri)[0];
190
	$params     = array_merge($parsedquery, $query);
191
192
	if(!empty($params)){
193
		$requestURI .= '?'.build_http_query($params);
194
	}
195
196
	return $requestURI;
197
}
198
199
/**
200
 * Return an UploadedFile instance array.
201
 *
202
 * @param array $files A array which respect $_FILES structure
203
 *
204
 * @throws \InvalidArgumentException for unrecognized values
205
 * @return array
206
 */
207
function normalize_files(array $files):array{
208
	$normalized = [];
209
210
	foreach($files as $key => $value){
211
212
		if($value instanceof UploadedFileInterface){
213
			$normalized[$key] = $value;
214
		}
215
		elseif(is_array($value) && isset($value['tmp_name'])){
216
			$normalized[$key] = create_uploaded_file_from_spec($value);
217
		}
218
		elseif(is_array($value)){
219
			$normalized[$key] = normalize_files($value);
220
			continue;
221
		}
222
		else{
223
			throw new InvalidArgumentException('Invalid value in files specification');
224
		}
225
226
	}
227
228
	return $normalized;
229
}
230
231
/**
232
 * Create and return an UploadedFile instance from a $_FILES specification.
233
 *
234
 * If the specification represents an array of values, this method will
235
 * delegate to normalizeNestedFileSpec() and return that return value.
236
 *
237
 * @param array $value $_FILES struct
238
 *
239
 * @return array|\Psr\Http\Message\UploadedFileInterface
240
 */
241
function create_uploaded_file_from_spec(array $value){
242
243
	if(is_array($value['tmp_name'])){
244
		return normalize_nested_file_spec($value);
245
	}
246
247
	return new UploadedFile($value['tmp_name'], (int)$value['size'], (int)$value['error'], $value['name'], $value['type']);
248
}
249
250
/**
251
 * Normalize an array of file specifications.
252
 *
253
 * Loops through all nested files and returns a normalized array of
254
 * UploadedFileInterface instances.
255
 *
256
 * @param array $files
257
 *
258
 * @return \Psr\Http\Message\UploadedFileInterface[]
259
 */
260
function normalize_nested_file_spec(array $files = []):array{
261
	$normalizedFiles = [];
262
263
	foreach(array_keys($files['tmp_name']) as $key){
264
		$spec = [
265
			'tmp_name' => $files['tmp_name'][$key],
266
			'size'     => $files['size'][$key],
267
			'error'    => $files['error'][$key],
268
			'name'     => $files['name'][$key],
269
			'type'     => $files['type'][$key],
270
		];
271
272
		$normalizedFiles[$key] = create_uploaded_file_from_spec($spec);
273
	}
274
275
	return $normalizedFiles;
276
}
277
278
/**
279
 * @todo
280
 *
281
 * @param \Psr\Http\Message\ResponseInterface $response
282
 * @param bool|null                           $assoc
283
 *
284
 * @return mixed
285
 */
286
function get_json(ResponseInterface $response, bool $assoc = null){
287
	return json_decode($response->getBody()->getContents(), $assoc);
288
}
289
290
/**
291
 * @todo
292
 *
293
 * @param \Psr\Http\Message\ResponseInterface $response
294
 *
295
 * @return \SimpleXMLElement
296
 */
297
function get_xml(ResponseInterface $response){
298
	return simplexml_load_string($response->getBody()->getContents());
299
}
300