PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.10.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.10.0
4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Traits / SerializeTrait.php
wp-staging / Framework / Traits Last commit date
ApplyFiltersTrait.php 3 months ago ArrayableTrait.php 8 months ago BatchSizeCalculateTrait.php 8 months ago BearerTokenTrait.php 6 months ago BenchmarkTrait.php 3 years ago BooleanTransientTrait.php 5 years ago DatabaseSearchReplaceTrait.php 1 month ago DbRowsGeneratorTrait.php 4 years ago DebugLogTrait.php 1 year ago DeveloperTimerTrait.php 10 months ago EndOfLinePlaceholderTrait.php 1 year ago EventLoggerTrait.php 2 months ago FileScanToCacheTrait.php 2 weeks ago FormatTrait.php 1 year ago HttpRequestTrait.php 10 months ago HydrateTrait.php 1 year ago I18nTrait.php 1 year ago IpResolverTrait.php 11 months ago JobResponseTrait.php 4 days ago MaintenanceTrait.php 6 months ago MemoryExhaustTrait.php 2 years ago MySQLRowsGeneratorTrait.php 8 months ago NoticesTrait.php 2 weeks ago PropertyConstructor.php 5 years ago RenameTmpDirectoryTrait.php 6 months ago ResourceTrait.php 6 months ago RestRequestTrait.php 5 months ago RestoreFileExclusionTrait.php 1 year ago SafeFileInfoTrait.php 2 weeks ago SerializeTrait.php 4 days ago SetTimeLimitTrait.php 2 months ago SlashTrait.php 1 year ago SqlCommentTrait.php 5 months ago TablePrefixValidator.php 5 months ago UrlTrait.php 1 year ago ValueGetterTrait.php 2 years ago WindowsOsTrait.php 1 year ago
SerializeTrait.php
163 lines
1 <?php
2
3 namespace WPStaging\Framework\Traits;
4
5 use __PHP_Incomplete_Class;
6
7 trait SerializeTrait
8 {
9 /**
10 * @param mixed $data
11 * @param array $allowedClasses
12 * @param bool $rejected Deliberately untyped. Any non-nullable hint throws a TypeError when a caller passes an undeclared variable.
13 * @return mixed
14 */
15 protected function safeMaybeUnserialize($data, array $allowedClasses = [], &$rejected = false)
16 {
17 $rejected = false;
18
19 if (!is_string($data) || !$this->isSerialized($data)) {
20 return $data;
21 }
22
23 $data = trim($data);
24 $failedToParse = false;
25 $value = $this->unserializeQuietly($data, $allowedClasses, $failedToParse);
26
27 if ($value === false && $failedToParse) {
28 $rejected = true;
29 return false;
30 }
31
32 if ($this->containsForbiddenClass($value)) {
33 $rejected = true;
34 return false;
35 }
36
37 return $value;
38 }
39
40 /**
41 * @param string $data
42 * @param array $allowedClasses
43 * @param bool $failed
44 * @return mixed
45 */
46 private function unserializeQuietly(string $data, array $allowedClasses, &$failed = false)
47 {
48 $failed = false;
49
50 set_error_handler(function () use (&$failed) {
51 $failed = true;
52 return true;
53 });
54
55 try {
56 return unserialize($data, ['allowed_classes' => $allowedClasses]);
57 } finally {
58 restore_error_handler();
59 }
60 }
61
62 /**
63 * @param mixed $value
64 * @param int $remainingDepth
65 * @return bool
66 */
67 protected function containsForbiddenClass($value, int $remainingDepth = 20): bool
68 {
69 if ($value instanceof __PHP_Incomplete_Class) {
70 return true;
71 }
72
73 if (is_object($value)) {
74 $value = (array)$value;
75 }
76
77 if (!is_array($value)) {
78 return false;
79 }
80
81 if ($remainingDepth < 1) {
82 return true;
83 }
84
85 foreach ($value as $item) {
86 if ($this->containsForbiddenClass($item, $remainingDepth - 1)) {
87 return true;
88 }
89 }
90
91 return false;
92 }
93
94 /**
95 * @see https://developer.wordpress.org/reference/functions/is_serialized/
96 * @return bool
97 */
98 protected function isSerialized(string $data, bool $strict = true): bool
99 {
100 if (!is_string($data)) {
101 return false;
102 }
103
104 $data = trim($data);
105 if ($data === 'N;') {
106 return true;
107 }
108
109 if (strlen($data) < 4) {
110 return false;
111 }
112
113 if ($data[1] !== ':') {
114 return false;
115 }
116
117 if ($strict) {
118 $lastc = substr($data, -1);
119 if ($lastc !== ';' && $lastc !== '}') {
120 return false;
121 }
122 } else {
123 $semicolon = strpos($data, ';');
124 $brace = strpos($data, '}');
125 if ($semicolon === false && $brace === false) {
126 return false;
127 }
128
129 if ($semicolon !== false && $semicolon < 3) {
130 return false;
131 }
132
133 if ($brace !== false && $brace < 4) {
134 return false;
135 }
136 }
137
138 $token = $data[0];
139 switch ($token) {
140 case 's':
141 if ($strict) {
142 if ('"' !== substr($data, -2, 1)) {
143 return false;
144 }
145 } elseif (function_exists('str_contains') && !str_contains($data, '"') || strpos($data, '"') === false) {
146 return false;
147 }
148 // Or else fall through.
149 case 'a':
150 case 'O':
151 case 'E':
152 return (bool) preg_match("/^{$token}:[0-9]+:/s", $data);
153 case 'b':
154 case 'i':
155 case 'd':
156 $end = $strict ? '$' : '';
157 return (bool) preg_match("/^{$token}:[0-9.E+-]+;$end/", $data);
158 }
159
160 return false;
161 }
162 }
163