PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.4.1
Defender Security – Malware Scanner, Login Security & Firewall v5.4.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / lib / packages / Laravel / SerializableClosure / Serializers / Native.php

Native.php in Defender Security – Malware Scanner, Login Security & Firewall 5.4.1, at lib/packages/Laravel/SerializableClosure/Serializers/Native.php

515 lines 14.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Serializers;
4
5 use Closure;
6 use DateTimeInterface;
7 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Contracts\Serializable;
8 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\SerializableClosure;
9 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ClosureScope;
10 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ClosureStream;
11 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ReflectionClosure;
12 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\SelfReference;
13 use WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\UnsignedSerializableClosure;
14 use ReflectionObject;
15 use UnitEnum;
16
17 class Native implements Serializable
18 {
19 /**
20 * Transform the use variables before serialization.
21 *
22 * @var \Closure|null
23 */
24 public static $transformUseVariables;
25
26 /**
27 * Resolve the use variables after unserialization.
28 *
29 * @var \Closure|null
30 */
31 public static $resolveUseVariables;
32
33 /**
34 * The closure to be serialized/unserialized.
35 *
36 * @var \Closure
37 */
38 protected $closure;
39
40 /**
41 * The closure's reflection.
42 *
43 * @var \WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ReflectionClosure|null
44 */
45 protected $reflector;
46
47 /**
48 * The closure's code.
49 *
50 * @var array|null
51 */
52 protected $code;
53
54 /**
55 * The closure's reference.
56 *
57 * @var string
58 */
59 protected $reference;
60
61 /**
62 * The closure's scope.
63 *
64 * @var \WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ClosureScope|null
65 */
66 protected $scope;
67
68 /**
69 * The "key" that marks an array as recursive.
70 */
71 const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY';
72
73 /**
74 * Creates a new serializable closure instance.
75 *
76 * @param \Closure $closure
77 * @return void
78 */
79 public function __construct(Closure $closure)
80 {
81 $this->closure = $closure;
82 }
83
84 /**
85 * Resolve the closure with the given arguments.
86 *
87 * @return mixed
88 */
89 public function __invoke()
90 {
91 return call_user_func_array($this->closure, func_get_args());
92 }
93
94 /**
95 * Gets the closure.
96 *
97 * @return \Closure
98 */
99 public function getClosure()
100 {
101 return $this->closure;
102 }
103
104 /**
105 * Get the serializable representation of the closure.
106 *
107 * @return array
108 */
109 public function __serialize()
110 {
111 if ($this->scope === null) {
112 $this->scope = new ClosureScope();
113 $this->scope->toSerialize++;
114 }
115
116 $this->scope->serializations++;
117
118 $scope = $object = null;
119 $reflector = $this->getReflector();
120
121 if ($reflector->isBindingRequired()) {
122 $object = $reflector->getClosureThis();
123
124 static::wrapClosures($object, $this->scope);
125 }
126
127 if ($scope = $reflector->getClosureScopeClass()) {
128 $scope = $scope->name;
129 }
130
131 $this->reference = spl_object_hash($this->closure);
132
133 $this->scope[$this->closure] = $this;
134
135 $use = $reflector->getUseVariables();
136
137 if (static::$transformUseVariables) {
138 $use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables());
139 }
140
141 $code = $reflector->getCode();
142
143 $this->mapByReference($use);
144
145 $data = [
146 'use' => $use,
147 'function' => $code,
148 'scope' => $scope,
149 'this' => $object,
150 'self' => $this->reference,
151 ];
152
153 if (! --$this->scope->serializations && ! --$this->scope->toSerialize) {
154 $this->scope = null;
155 }
156
157 return $data;
158 }
159
160 /**
161 * Restore the closure after serialization.
162 *
163 * @param array $data
164 * @return void
165 */
166 public function __unserialize($data)
167 {
168 ClosureStream::register();
169
170 $this->code = $data;
171 unset($data);
172
173 $this->code['objects'] = [];
174
175 if ($this->code['use']) {
176 $this->scope = new ClosureScope();
177
178 if (static::$resolveUseVariables) {
179 $this->code['use'] = call_user_func(static::$resolveUseVariables, $this->code['use']);
180 }
181
182 $this->mapPointers($this->code['use']);
183
184 extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS);
185
186 $this->scope = null;
187 }
188
189 $this->closure = include ClosureStream::STREAM_PROTO.'://'.$this->code['function'];
190
191 if ($this->code['this'] === $this) {
192 $this->code['this'] = null;
193 }
194
195 $this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);
196
197 if (! empty($this->code['objects'])) {
198 foreach ($this->code['objects'] as $item) {
199 $item['property']->setValue($item['instance'], $item['object']->getClosure());
200 }
201 }
202
203 $this->code = $this->code['function'];
204 }
205
206 /**
207 * Ensures the given closures are serializable.
208 *
209 * @param mixed $data
210 * @param \WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ClosureScope $storage
211 * @return void
212 */
213 public static function wrapClosures(&$data, $storage)
214 {
215 if ($data instanceof Closure) {
216 $data = new static($data);
217 } elseif (is_array($data)) {
218 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
219 return;
220 }
221
222 $data[self::ARRAY_RECURSIVE_KEY] = true;
223
224 foreach ($data as $key => &$value) {
225 if ($key === self::ARRAY_RECURSIVE_KEY) {
226 continue;
227 }
228 static::wrapClosures($value, $storage);
229 }
230
231 unset($value);
232 unset($data[self::ARRAY_RECURSIVE_KEY]);
233 } elseif ($data instanceof \stdClass) {
234 if (isset($storage[$data])) {
235 $data = $storage[$data];
236
237 return;
238 }
239
240 $data = $storage[$data] = clone $data;
241
242 foreach ($data as &$value) {
243 static::wrapClosures($value, $storage);
244 }
245
246 unset($value);
247 } elseif (is_object($data) && ! $data instanceof static && ! $data instanceof UnitEnum) {
248 if (isset($storage[$data])) {
249 $data = $storage[$data];
250
251 return;
252 }
253
254 $instance = $data;
255 $reflection = new ReflectionObject($instance);
256
257 if (! $reflection->isUserDefined()) {
258 $storage[$instance] = $data;
259
260 return;
261 }
262
263 $storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();
264
265 do {
266 if (! $reflection->isUserDefined()) {
267 break;
268 }
269
270 foreach ($reflection->getProperties() as $property) {
271 if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
272 continue;
273 }
274
275 $property->setAccessible(true);
276
277 if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {
278 continue;
279 }
280
281 $value = $property->getValue($instance);
282
283 if (is_array($value) || is_object($value)) {
284 static::wrapClosures($value, $storage);
285 }
286
287 $property->setValue($data, $value);
288 }
289 } while ($reflection = $reflection->getParentClass());
290 }
291 }
292
293 /**
294 * Gets the closure's reflector.
295 *
296 * @return \WPMU_DEV\Defender\Vendor\Laravel\SerializableClosure\Support\ReflectionClosure
297 */
298 public function getReflector()
299 {
300 if ($this->reflector === null) {
301 $this->code = null;
302 $this->reflector = new ReflectionClosure($this->closure);
303 }
304
305 return $this->reflector;
306 }
307
308 /**
309 * Internal method used to map closure pointers.
310 *
311 * @param mixed $data
312 * @return void
313 */
314 protected function mapPointers(&$data)
315 {
316 $scope = $this->scope;
317
318 if ($data instanceof static) {
319 $data = &$data->closure;
320 } elseif (is_array($data)) {
321 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
322 return;
323 }
324
325 $data[self::ARRAY_RECURSIVE_KEY] = true;
326
327 foreach ($data as $key => &$value) {
328 if ($key === self::ARRAY_RECURSIVE_KEY) {
329 continue;
330 } elseif ($value instanceof static) {
331 $data[$key] = &$value->closure;
332 } elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) {
333 $data[$key] = &$this->closure;
334 } else {
335 $this->mapPointers($value);
336 }
337 }
338
339 unset($value);
340 unset($data[self::ARRAY_RECURSIVE_KEY]);
341 } elseif ($data instanceof \stdClass) {
342 if (isset($scope[$data])) {
343 return;
344 }
345
346 $scope[$data] = true;
347
348 foreach ($data as $key => &$value) {
349 if ($value instanceof SelfReference && $value->hash === $this->code['self']) {
350 $data->{$key} = &$this->closure;
351 } elseif (is_array($value) || is_object($value)) {
352 $this->mapPointers($value);
353 }
354 }
355
356 unset($value);
357 } elseif (is_object($data) && ! ($data instanceof Closure)) {
358 if (isset($scope[$data])) {
359 return;
360 }
361
362 $scope[$data] = true;
363 $reflection = new ReflectionObject($data);
364
365 do {
366 if (! $reflection->isUserDefined()) {
367 break;
368 }
369
370 foreach ($reflection->getProperties() as $property) {
371 if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
372 continue;
373 }
374
375 $property->setAccessible(true);
376
377 if (PHP_VERSION >= 7.4 && ! $property->isInitialized($data)) {
378 continue;
379 }
380
381 $item = $property->getValue($data);
382
383 if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
384 $this->code['objects'][] = [
385 'instance' => $data,
386 'property' => $property,
387 'object' => $item instanceof SelfReference ? $this : $item,
388 ];
389 } elseif (is_array($item) || is_object($item)) {
390 $this->mapPointers($item);
391 $property->setValue($data, $item);
392 }
393 }
394 } while ($reflection = $reflection->getParentClass());
395 }
396 }
397
398 /**
399 * Internal method used to map closures by reference.
400 *
401 * @param mixed $data
402 * @return void
403 */
404 protected function mapByReference(&$data)
405 {
406 if ($data instanceof Closure) {
407 if ($data === $this->closure) {
408 $data = new SelfReference($this->reference);
409
410 return;
411 }
412
413 if (isset($this->scope[$data])) {
414 $data = $this->scope[$data];
415
416 return;
417 }
418
419 $instance = new static($data);
420
421 $instance->scope = $this->scope;
422
423 $data = $this->scope[$data] = $instance;
424 } elseif (is_array($data)) {
425 if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
426 return;
427 }
428
429 $data[self::ARRAY_RECURSIVE_KEY] = true;
430
431 foreach ($data as $key => &$value) {
432 if ($key === self::ARRAY_RECURSIVE_KEY) {
433 continue;
434 }
435
436 $this->mapByReference($value);
437 }
438
439 unset($value);
440 unset($data[self::ARRAY_RECURSIVE_KEY]);
441 } elseif ($data instanceof \stdClass) {
442 if (isset($this->scope[$data])) {
443 $data = $this->scope[$data];
444
445 return;
446 }
447
448 $instance = $data;
449 $this->scope[$instance] = $data = clone $data;
450
451 foreach ($data as &$value) {
452 $this->mapByReference($value);
453 }
454
455 unset($value);
456 } elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) {
457 if (isset($this->scope[$data])) {
458 $data = $this->scope[$data];
459
460 return;
461 }
462
463 $instance = $data;
464
465 if ($data instanceof DateTimeInterface) {
466 $this->scope[$instance] = $data;
467
468 return;
469 }
470
471 if ($data instanceof UnitEnum) {
472 $this->scope[$instance] = $data;
473
474 return;
475 }
476
477 $reflection = new ReflectionObject($data);
478
479 if (! $reflection->isUserDefined()) {
480 $this->scope[$instance] = $data;
481
482 return;
483 }
484
485 $this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();
486
487 do {
488 if (! $reflection->isUserDefined()) {
489 break;
490 }
491
492 foreach ($reflection->getProperties() as $property) {
493 if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
494 continue;
495 }
496
497 $property->setAccessible(true);
498
499 if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {
500 continue;
501 }
502
503 $value = $property->getValue($instance);
504
505 if (is_array($value) || is_object($value)) {
506 $this->mapByReference($value);
507 }
508
509 $property->setValue($data, $value);
510 }
511 } while ($reflection = $reflection->getParentClass());
512 }
513 }
514 }
515