PluginProbe
YayMail – WooCommerce Email Customizer / 4.4.7
YayMail – WooCommerce Email Customizer v4.4.7
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 trunk 1.9.6 2.1.4 2.1.5 3.2.2 3.2.6 3.2.7.1 3.2.8.1 3.2.9 3.3 3.3.1 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4 All 58 releases
yaymail / src / Utils / SafeUnserializer.php

SafeUnserializer.php in YayMail – WooCommerce Email Customizer 4.4.7, at src/Utils/SafeUnserializer.php

157 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace YayMail\Utils;
4
5 defined( 'ABSPATH' ) || exit;
6
7 /**
8 * Unserialize backup/import values without instantiating gadgets.
9 * stdClass is allowed (YayMail exports); any other class is rejected.
10 */
11 class SafeUnserializer {
12
13 /**
14 * Max recursion depth.
15 */
16 const MAX_DEPTH = 128;
17
18 /**
19 * Unserialize with allowed_classes => false.
20 *
21 * @param mixed $value Raw value, usually a serialized string.
22 * @return mixed
23 */
24 public static function decode( $value ) {
25 if ( ! is_string( $value ) ) {
26 return $value;
27 }
28
29 if ( ! function_exists( 'is_serialized' ) || ! is_serialized( $value ) ) {
30 return $value;
31 }
32
33 $unserialized = @unserialize( $value, [ 'allowed_classes' => false ] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.Security.SafeUnserialize.unserialize_unserialize -- no class is instantiated, and callers reject leftover objects.
34
35 if ( false === $unserialized && 'b:0;' !== $value ) {
36 return $value;
37 }
38
39 return $unserialized;
40 }
41
42 /**
43 * Unserialize a stored backup option. Backup rows from $wpdb are stdClass,
44 * so stdClass must stay a real object for restore to read its properties.
45 *
46 * @param mixed $value Raw value, usually a serialized string.
47 * @return mixed
48 */
49 public static function decode_backup( $value ) {
50 if ( ! is_string( $value ) || ! is_serialized( $value ) ) {
51 return $value;
52 }
53
54 $unserialized = @unserialize( $value, [ 'allowed_classes' => [ 'stdClass' ] ] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.Security.SafeUnserialize.unserialize_unserialize -- only stdClass may be instantiated.
55
56 if ( false === $unserialized && 'b:0;' !== $value ) {
57 return $value;
58 }
59
60 return $unserialized;
61 }
62
63 /**
64 * Unserialize a value that is about to be written to the database.
65 *
66 * @param mixed $value Raw value, usually a serialized string.
67 * @return mixed
68 * @throws \Exception When the payload carries a non-stdClass object at any depth.
69 */
70 public static function decode_strict( $value ) {
71 $decoded = self::decode( $value );
72
73 if ( self::contains_object( $decoded ) ) {
74 throw new \Exception( 'Serialized PHP objects are not allowed in imported data.' );
75 }
76
77 return $decoded;
78 }
79
80 /**
81 * True if a non-stdClass object exists at any depth.
82 *
83 * @param mixed $value Decoded value.
84 * @param int $depth Current recursion depth.
85 * @return bool
86 */
87 public static function contains_object( $value, $depth = 0 ) {
88 if ( $depth >= self::MAX_DEPTH ) {
89 return true;
90 }
91
92 if ( is_object( $value ) ) {
93 if ( ! self::is_stdclass( $value ) ) {
94 return true;
95 }
96
97 $value = self::object_vars( $value );
98 }
99
100 if ( ! is_array( $value ) ) {
101 return false;
102 }
103
104 foreach ( $value as $item ) {
105 if ( self::contains_object( $item, $depth + 1 ) ) {
106 return true;
107 }
108 }
109
110 return false;
111 }
112
113 /**
114 * Real stdClass or its incomplete stand-in.
115 *
116 * @param object $value Decoded object.
117 * @return bool
118 */
119 private static function is_stdclass( $value ) {
120 if ( $value instanceof \stdClass ) {
121 return true;
122 }
123
124 if ( ! $value instanceof \__PHP_Incomplete_Class ) {
125 return false;
126 }
127
128 $vars = self::object_vars( $value );
129
130 return isset( $vars['__PHP_Incomplete_Class_Name'] ) && 'stdClass' === $vars['__PHP_Incomplete_Class_Name'];
131 }
132
133 /**
134 * Properties of an object, including incomplete objects.
135 *
136 * @param object $value Object to inspect.
137 * @return array
138 */
139 private static function object_vars( $value ) {
140 if ( function_exists( 'get_mangled_object_vars' ) ) {
141 return get_mangled_object_vars( $value );
142 }
143
144 return get_object_vars( $value );
145 }
146
147 /**
148 * True if the serialized value contains a non-stdClass object.
149 *
150 * @param mixed $value Raw value, usually a serialized string.
151 * @return bool
152 */
153 public static function has_object_payload( $value ) {
154 return self::contains_object( self::decode( $value ) );
155 }
156 }
157