1: <?php
2: /**
3: * Serializer class.
4: *
5: * @package Number
6: * @version 1.0.1
7: * @author Vee W.
8: * @license http://opensource.org/licenses/MIT MIT
9: */
10:
11:
12: namespace Rundiz\Serializer;
13:
14:
15: /**
16: * Works with serialization such as check if string is serialized.
17: *
18: * @author Vee W.
19: * @since 1.0
20: */
21: class Serializer
22: {
23:
24:
25: /**
26: * Is serialized string.
27: *
28: * @link https://core.trac.wordpress.org/browser/tags/4.7.3/src/wp-includes/functions.php#L341 Reference from WordPress.
29: * @link https://gist.github.com/cs278/217091 Reference from Github cs278/is_serialized.php
30: * @param string $string The string to check.
31: * @return boolean Return true if serialized, false for otherwise.
32: */
33: public function isSerialized($string)
34: {
35: if (!is_string($string)) {
36: return false;
37: }
38:
39: $string = trim($string);
40:
41: if ($string === 'N;') {
42: // if serialized string is NULL.
43: return true;
44: }
45:
46: $string_encoding = mb_detect_encoding($string);
47: $length = mb_strlen($string, $string_encoding);
48: $last_char = mb_substr($string, -1, NULL, $string_encoding);
49: unset($string_encoding);
50:
51: if ($length < 4) {
52: // if total characters of this string (string length) is less than 4 then it is not serialized except NULL which is verified above.
53: unset($last_char, $length);
54: return false;
55: }
56:
57: if ($string[1] !== ':') {
58: // if character number 2 (offset 1, start at 0) from this string is not colon means it is not serialized string.
59: unset($last_char, $length);
60: return false;
61: }
62:
63: if (in_array($string[0], ['b', 'i', 'd', 's']) && $last_char !== ';') {
64: // if first character maybe boolean, integer, double or float, string but last character is not semicolon means it is not serialized string.
65: unset($last_char, $length);
66: return false;
67: } elseif (in_array($string[0], ['a', 'O']) && $last_char !== '}') {
68: // last character of array, object is not right curly bracket means it is not serialized string.
69: unset($last_char, $length);
70: return false;
71: }
72:
73: // switch to first character of this string.
74: switch ($string[0]) {
75: case 'b':
76: // this maybe boolean
77: if ($length > 4 || ($string[2] !== '0' && $string[2] !== '1')) {
78: // if string length is more than 4 or character number 3 (offset 2) is not 0 (false) and is not 1 (true) means it is not serialized string.
79: return false;
80: } elseif ($length == 4 && ($string[2] === '0' || $string[2] === '1')) {
81: // if string length is exactly 4 and character number 3 (offset 2) is 0 (false) or 1 (true) means it is serialized string.
82: return true;
83: } else {
84: return false;
85: }
86: case 'i':
87: // this maybe integer
88: return (boolean) preg_match('#^'.$string[0].':[0-9\-]+\\'.$last_char.'#', $string);
89: case 'd':
90: // this maybe double or float
91: return (boolean) preg_match('#^'.$string[0].':[0-9\.E\-\+]+\\'.$last_char.'#', $string);
92: case 's':
93: // this maybe string
94: $exp_string = explode(':', $string);
95: if (isset($exp_string[1]) && isset($exp_string[2])) {
96: // if found number of total characters in serialize, count to make sure that it is matched.
97: unset($last_char, $length);
98: // number in serialized string type seems to use `strlen` because it is not counting the real unicode characters.
99: return (intval($exp_string[1]) === intval(strlen(trim($exp_string[2], ';"'))));
100: }
101: unset($exp_string, $last_char, $length);
102: return false;
103: case 'a':
104: // this maybe array
105: case 'O':
106: // this maybe object
107: return (boolean) preg_match('#^'.$string[0].':[0-9]+\:#s', $string);
108: }// endswitch;
109:
110: return false;
111: }// isSerialized
112:
113:
114: /**
115: * Check first that data is serialized or not, if not then serialize it otherwise return as is.
116: *
117: * @param mixed $value The data to be serialize.
118: * @return string Return serialized string.
119: */
120: public function maybeSerialize($value)
121: {
122: if ($this->isSerialized($value) === true) {
123: return $value;
124: }
125: return @serialize($value);
126: }// maybeSerialize
127:
128:
129: /**
130: * Check first that data is serialized or not, if yes then unserialize it otherwise return as is.
131: *
132: * @since 1.0.1
133: * @param mixed $value The data to be unserialize.
134: * @return mixed Return unserialized value.
135: */
136: public function maybeUnserialize($value)
137: {
138: if ($this->isSerialized($value) === false) {
139: return $value;
140: }
141: return @unserialize($value);
142: }// maybeUnserialize
143:
144:
145: }