PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.9.5
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.9.5
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 5 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 9 months ago EndOfLinePlaceholderTrait.php 1 year ago EventLoggerTrait.php 2 months ago FileScanToCacheTrait.php 1 week ago FormatTrait.php 1 year ago HttpRequestTrait.php 9 months ago HydrateTrait.php 1 year ago I18nTrait.php 1 year ago IpResolverTrait.php 11 months ago MaintenanceTrait.php 6 months ago MemoryExhaustTrait.php 2 years ago MySQLRowsGeneratorTrait.php 8 months ago NoticesTrait.php 1 week ago PropertyConstructor.php 5 years ago RenameTmpDirectoryTrait.php 6 months ago ResourceTrait.php 5 months ago RestRequestTrait.php 4 months ago RestoreFileExclusionTrait.php 1 year ago SafeFileInfoTrait.php 1 week ago SerializeTrait.php 3 days ago SetTimeLimitTrait.php 2 months ago SlashTrait.php 1 year ago SqlCommentTrait.php 4 months ago TablePrefixValidator.php 4 months ago UrlTrait.php 1 year ago ValueGetterTrait.php 2 years ago WindowsOsTrait.php 1 year ago
SerializeTrait.php
147 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 * @return mixed
13 */
14 protected function safeMaybeUnserialize($data, array $allowedClasses = [])
15 {
16 if (!is_string($data) || !$this->isSerialized($data)) {
17 return $data;
18 }
19
20 $value = $this->unserializeQuietly(trim($data), $allowedClasses);
21 if ($this->containsForbiddenClass($value)) {
22 return false;
23 }
24
25 return $value;
26 }
27
28 /**
29 * @param string $data
30 * @param array $allowedClasses
31 * @return mixed
32 */
33 private function unserializeQuietly(string $data, array $allowedClasses)
34 {
35 set_error_handler(function () {
36 return true;
37 });
38
39 try {
40 return unserialize($data, ['allowed_classes' => $allowedClasses]);
41 } finally {
42 restore_error_handler();
43 }
44 }
45
46 /**
47 * @param mixed $value
48 * @param int $remainingDepth
49 * @return bool
50 */
51 protected function containsForbiddenClass($value, int $remainingDepth = 20): bool
52 {
53 if ($value instanceof __PHP_Incomplete_Class) {
54 return true;
55 }
56
57 if (is_object($value)) {
58 $value = (array)$value;
59 }
60
61 if (!is_array($value)) {
62 return false;
63 }
64
65 if ($remainingDepth < 1) {
66 return true;
67 }
68
69 foreach ($value as $item) {
70 if ($this->containsForbiddenClass($item, $remainingDepth - 1)) {
71 return true;
72 }
73 }
74
75 return false;
76 }
77
78 /**
79 * @see https://developer.wordpress.org/reference/functions/is_serialized/
80 * @return bool
81 */
82 protected function isSerialized(string $data, bool $strict = true): bool
83 {
84 if (!is_string($data)) {
85 return false;
86 }
87
88 $data = trim($data);
89 if ($data === 'N;') {
90 return true;
91 }
92
93 if (strlen($data) < 4) {
94 return false;
95 }
96
97 if ($data[1] !== ':') {
98 return false;
99 }
100
101 if ($strict) {
102 $lastc = substr($data, -1);
103 if ($lastc !== ';' && $lastc !== '}') {
104 return false;
105 }
106 } else {
107 $semicolon = strpos($data, ';');
108 $brace = strpos($data, '}');
109 if ($semicolon === false && $brace === false) {
110 return false;
111 }
112
113 if ($semicolon !== false && $semicolon < 3) {
114 return false;
115 }
116
117 if ($brace !== false && $brace < 4) {
118 return false;
119 }
120 }
121
122 $token = $data[0];
123 switch ($token) {
124 case 's':
125 if ($strict) {
126 if ('"' !== substr($data, -2, 1)) {
127 return false;
128 }
129 } elseif (function_exists('str_contains') && !str_contains($data, '"') || strpos($data, '"') === false) {
130 return false;
131 }
132 // Or else fall through.
133 case 'a':
134 case 'O':
135 case 'E':
136 return (bool) preg_match("/^{$token}:[0-9]+:/s", $data);
137 case 'b':
138 case 'i':
139 case 'd':
140 $end = $strict ? '$' : '';
141 return (bool) preg_match("/^{$token}:[0-9.E+-]+;$end/", $data);
142 }
143
144 return false;
145 }
146 }
147