PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / Api / Validator.php
transferito / vendor / aws / aws-sdk-php / src / Api Last commit date
ErrorParser 11 months ago Parser 11 months ago Serializer 11 months ago AbstractModel.php 11 months ago ApiProvider.php 11 months ago DateTimeResult.php 11 months ago DocModel.php 11 months ago ListShape.php 11 months ago MapShape.php 11 months ago Operation.php 11 months ago Service.php 11 months ago Shape.php 11 months ago ShapeMap.php 11 months ago StructureShape.php 11 months ago TimestampShape.php 11 months ago Validator.php 11 months ago
Validator.php
347 lines
1 <?php
2 namespace Aws\Api;
3
4 use Aws;
5
6 /**
7 * Validates a schema against a hash of input.
8 */
9 class Validator
10 {
11 private $path = [];
12 private $errors = [];
13 private $constraints = [];
14
15 private static $defaultConstraints = [
16 'required' => true,
17 'min' => true,
18 'max' => false,
19 'pattern' => false
20 ];
21
22 /**
23 * @param array $constraints Associative array of constraints to enforce.
24 * Accepts the following keys: "required", "min",
25 * "max", and "pattern". If a key is not
26 * provided, the constraint will assume false.
27 */
28 public function __construct(array $constraints = null)
29 {
30 static $assumedFalseValues = [
31 'required' => false,
32 'min' => false,
33 'max' => false,
34 'pattern' => false
35 ];
36 $this->constraints = empty($constraints)
37 ? self::$defaultConstraints
38 : $constraints + $assumedFalseValues;
39 }
40
41 /**
42 * Validates the given input against the schema.
43 *
44 * @param string $name Operation name
45 * @param Shape $shape Shape to validate
46 * @param array $input Input to validate
47 *
48 * @throws \InvalidArgumentException if the input is invalid.
49 */
50 public function validate($name, Shape $shape, array $input)
51 {
52 $this->dispatch($shape, $input);
53
54 if ($this->errors) {
55 $message = sprintf(
56 "Found %d error%s while validating the input provided for the "
57 . "%s operation:\n%s",
58 count($this->errors),
59 count($this->errors) > 1 ? 's' : '',
60 $name,
61 implode("\n", $this->errors)
62 );
63 $this->errors = [];
64
65 throw new \InvalidArgumentException($message);
66 }
67 }
68
69 private function dispatch(Shape $shape, $value)
70 {
71 static $methods = [
72 'structure' => 'check_structure',
73 'list' => 'check_list',
74 'map' => 'check_map',
75 'blob' => 'check_blob',
76 'boolean' => 'check_boolean',
77 'integer' => 'check_numeric',
78 'float' => 'check_numeric',
79 'long' => 'check_numeric',
80 'string' => 'check_string',
81 'byte' => 'check_string',
82 'char' => 'check_string'
83 ];
84
85 $type = $shape->getType();
86 if (isset($methods[$type])) {
87 $this->{$methods[$type]}($shape, $value);
88 }
89 }
90
91 private function check_structure(StructureShape $shape, $value)
92 {
93 $isDocument = (isset($shape['document']) && $shape['document']);
94 $isUnion = (isset($shape['union']) && $shape['union']);
95 if ($isDocument) {
96 if (!$this->checkDocumentType($value)) {
97 $this->addError("is not a valid document type");
98 return;
99 }
100 } elseif ($isUnion) {
101 if (!$this->checkUnion($value)) {
102 $this->addError("is a union type and must have exactly one non null value");
103 return;
104 }
105 } elseif (!$this->checkAssociativeArray($value)) {
106 return;
107 }
108
109 if ($this->constraints['required'] && $shape['required']) {
110 foreach ($shape['required'] as $req) {
111 if (!isset($value[$req])) {
112 $this->path[] = $req;
113 $this->addError('is missing and is a required parameter');
114 array_pop($this->path);
115 }
116 }
117 }
118 if (!$isDocument) {
119 foreach ($value as $name => $v) {
120 if ($shape->hasMember($name)) {
121 $this->path[] = $name;
122 $this->dispatch(
123 $shape->getMember($name),
124 isset($value[$name]) ? $value[$name] : null
125 );
126 array_pop($this->path);
127 }
128 }
129 }
130 }
131
132 private function check_list(ListShape $shape, $value)
133 {
134 if (!is_array($value)) {
135 $this->addError('must be an array. Found '
136 . Aws\describe_type($value));
137 return;
138 }
139
140 $this->validateRange($shape, count($value), "list element count");
141
142 $items = $shape->getMember();
143 foreach ($value as $index => $v) {
144 $this->path[] = $index;
145 $this->dispatch($items, $v);
146 array_pop($this->path);
147 }
148 }
149
150 private function check_map(MapShape $shape, $value)
151 {
152 if (!$this->checkAssociativeArray($value)) {
153 return;
154 }
155
156 $values = $shape->getValue();
157 foreach ($value as $key => $v) {
158 $this->path[] = $key;
159 $this->dispatch($values, $v);
160 array_pop($this->path);
161 }
162 }
163
164 private function check_blob(Shape $shape, $value)
165 {
166 static $valid = [
167 'string' => true,
168 'integer' => true,
169 'double' => true,
170 'resource' => true
171 ];
172
173 $type = gettype($value);
174 if (!isset($valid[$type])) {
175 if ($type != 'object' || !method_exists($value, '__toString')) {
176 $this->addError('must be an fopen resource, a '
177 . 'GuzzleHttp\Stream\StreamInterface object, or something '
178 . 'that can be cast to a string. Found '
179 . Aws\describe_type($value));
180 }
181 }
182 }
183
184 private function check_numeric(Shape $shape, $value)
185 {
186 if (!is_numeric($value)) {
187 $this->addError('must be numeric. Found '
188 . Aws\describe_type($value));
189 return;
190 }
191
192 $this->validateRange($shape, $value, "numeric value");
193 }
194
195 private function check_boolean(Shape $shape, $value)
196 {
197 if (!is_bool($value)) {
198 $this->addError('must be a boolean. Found '
199 . Aws\describe_type($value));
200 }
201 }
202
203 private function check_string(Shape $shape, $value)
204 {
205 if ($shape['jsonvalue']) {
206 if (!self::canJsonEncode($value)) {
207 $this->addError('must be a value encodable with \'json_encode\'.'
208 . ' Found ' . Aws\describe_type($value));
209 }
210 return;
211 }
212
213 if (!$this->checkCanString($value)) {
214 $this->addError('must be a string or an object that implements '
215 . '__toString(). Found ' . Aws\describe_type($value));
216 return;
217 }
218
219 $value = isset($value) ? $value : '';
220 $this->validateRange($shape, strlen($value), "string length");
221
222 if ($this->constraints['pattern']) {
223 $pattern = $shape['pattern'];
224 if ($pattern && !preg_match("/$pattern/", $value)) {
225 $this->addError("Pattern /$pattern/ failed to match '$value'");
226 }
227 }
228 }
229
230 private function validateRange(Shape $shape, $length, $descriptor)
231 {
232 if ($this->constraints['min']) {
233 $min = $shape['min'];
234 if ($min && $length < $min) {
235 $this->addError("expected $descriptor to be >= $min, but "
236 . "found $descriptor of $length");
237 }
238 }
239
240 if ($this->constraints['max']) {
241 $max = $shape['max'];
242 if ($max && $length > $max) {
243 $this->addError("expected $descriptor to be <= $max, but "
244 . "found $descriptor of $length");
245 }
246 }
247 }
248
249 private function checkArray($arr)
250 {
251 return $this->isIndexed($arr) || $this->isAssociative($arr);
252 }
253
254 private function isAssociative($arr)
255 {
256 return count(array_filter(array_keys($arr), "is_string")) == count($arr);
257 }
258
259 private function isIndexed(array $arr)
260 {
261 return $arr == array_values($arr);
262 }
263
264 private function checkCanString($value)
265 {
266 static $valid = [
267 'string' => true,
268 'integer' => true,
269 'double' => true,
270 'NULL' => true,
271 ];
272
273 $type = gettype($value);
274
275 return isset($valid[$type]) ||
276 ($type == 'object' && method_exists($value, '__toString'));
277 }
278
279 private function checkAssociativeArray($value)
280 {
281 $isAssociative = false;
282
283 if (is_array($value)) {
284 $expectedIndex = 0;
285 $key = key($value);
286
287 do {
288 $isAssociative = $key !== $expectedIndex++;
289 next($value);
290 $key = key($value);
291 } while (!$isAssociative && null !== $key);
292 }
293
294 if (!$isAssociative) {
295 $this->addError('must be an associative array. Found '
296 . Aws\describe_type($value));
297 return false;
298 }
299
300 return true;
301 }
302
303 private function checkDocumentType($value)
304 {
305 if (is_array($value)) {
306 $typeOfFirstKey = gettype(key($value));
307 foreach ($value as $key => $val) {
308 if (!$this->checkDocumentType($val) || gettype($key) != $typeOfFirstKey) {
309 return false;
310 }
311 }
312 return $this->checkArray($value);
313 }
314 return is_null($value)
315 || is_numeric($value)
316 || is_string($value)
317 || is_bool($value);
318 }
319
320 private function checkUnion($value)
321 {
322 if (is_array($value)) {
323 $nonNullCount = 0;
324 foreach ($value as $key => $val) {
325 if (!is_null($val) && !(strpos($key, "@") === 0)) {
326 $nonNullCount++;
327 }
328 }
329 return $nonNullCount == 1;
330 }
331 return !is_null($value);
332 }
333
334 private function addError($message)
335 {
336 $this->errors[] =
337 implode('', array_map(function ($s) { return "[{$s}]"; }, $this->path))
338 . ' '
339 . $message;
340 }
341
342 private function canJsonEncode($data)
343 {
344 return !is_resource($data);
345 }
346 }
347