PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.24
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.24
1.10.25 1.10.24 1.10.23 1.10.22 1.10.21 1.10.20 1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 All 169 releases
woocommerce-pos / vendor_prefixed / sentry / sentry / src / Serializer / AbstractSerializer.php

AbstractSerializer.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.24, at vendor_prefixed/sentry/sentry/src/Serializer/AbstractSerializer.php

341 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare (strict_types=1);
4 /*
5 * Copyright 2012 Facebook, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19 namespace WCPOS\Vendor\Sentry\Serializer;
20
21 use WCPOS\Vendor\Sentry\Options;
22 /**
23 * This helper is based on code from Facebook's Phabricator project.
24 *
25 * https://github.com/facebook/phabricator
26 *
27 * Specifically, it is an adaptation of the PhutilReadableSerializer class.
28 */
29 abstract class AbstractSerializer
30 {
31 /**
32 * The default mb detect order.
33 *
34 * @see http://php.net/manual/en/function.mb-detect-encoding.php
35 */
36 public const DEFAULT_MB_DETECT_ORDER = 'auto';
37 /**
38 * Suggested detect order for western countries.
39 */
40 public const WESTERN_MB_DETECT_ORDER = 'UTF-8, ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, Windows-1251, Windows-1252, Windows-1254';
41 /**
42 * The maximum depth to reach when serializing recursively.
43 *
44 * @var int
45 */
46 private $maxDepth;
47 /**
48 * This is the default mb detect order for the detection of encoding.
49 *
50 * @var string
51 */
52 protected $mbDetectOrder = self::DEFAULT_MB_DETECT_ORDER;
53 /**
54 * @var bool Flag to enable serialization of objects internal properties
55 */
56 protected $serializeAllObjects = \false;
57 /**
58 * @var Options The Sentry options
59 */
60 protected $options;
61 /**
62 * AbstractSerializer constructor.
63 *
64 * @param Options $options The SDK configuration options
65 */
66 public function __construct(Options $options, int $maxDepth = 3, ?string $mbDetectOrder = null)
67 {
68 $this->maxDepth = $maxDepth;
69 if ($mbDetectOrder != null) {
70 $this->mbDetectOrder = $mbDetectOrder;
71 }
72 $this->options = $options;
73 }
74 /**
75 * Serialize an object (recursively) into something safe for data
76 * sanitization and encoding.
77 *
78 * @param mixed $value
79 *
80 * @return string|bool|float|int|mixed[]|null
81 */
82 protected function serializeRecursively($value, int $_depth = 0)
83 {
84 try {
85 if ($_depth >= $this->maxDepth) {
86 return $this->serializeValue($value);
87 }
88 try {
89 if (@\is_callable($value)) {
90 return $this->serializeCallable($value);
91 }
92 } catch (\Throwable $exception) {
93 // Do nothing on purpose
94 }
95 if (\is_array($value)) {
96 $serializedArray = [];
97 foreach ($value as $k => $v) {
98 $serializedArray[$k] = $this->serializeRecursively($v, $_depth + 1);
99 }
100 return $serializedArray;
101 }
102 if (\is_object($value)) {
103 $classSerializers = $this->resolveClassSerializers($value);
104 // Try each serializer until there is none left or the serializer returned data
105 foreach ($classSerializers as $classSerializer) {
106 try {
107 $serializedObjectData = $classSerializer($value);
108 if (\is_array($serializedObjectData)) {
109 return ['class' => \get_class($value), 'data' => $this->serializeRecursively($serializedObjectData, $_depth + 1)];
110 }
111 } catch (\Throwable $e) {
112 // Ignore any exceptions generated by a class serializer
113 }
114 }
115 if ($value instanceof \DateTimeInterface) {
116 return $this->formatDate($value);
117 }
118 if ($value instanceof \UnitEnum) {
119 return $this->serializeValue($value);
120 }
121 if ($this->serializeAllObjects || $value instanceof \stdClass) {
122 return $this->serializeObject($value, $_depth);
123 }
124 }
125 return $this->serializeValue($value);
126 } catch (\Throwable $error) {
127 if (\is_string($value)) {
128 return $value . ' {serialization error}';
129 }
130 return '{serialization error}';
131 }
132 }
133 /**
134 * Find class serializers for a object.
135 *
136 * Registered serializers with the `class_serializers` option take precedence over
137 * objects implementing the `SerializableInterface`.
138 *
139 * @param object $object
140 *
141 * @return array<int, callable>
142 */
143 protected function resolveClassSerializers($object) : array
144 {
145 $serializers = [];
146 foreach ($this->options->getClassSerializers() as $type => $serializer) {
147 if ($object instanceof $type) {
148 $serializers[] = $serializer;
149 }
150 }
151 if ($object instanceof SerializableInterface) {
152 $serializers[] = static function (SerializableInterface $object) : ?array {
153 return $object->toSentry();
154 };
155 }
156 return $serializers;
157 }
158 /**
159 * @param object $object
160 * @param string[] $hashes
161 *
162 * @return mixed[]|string|bool|float|int|null
163 */
164 protected function serializeObject($object, int $_depth = 0, array $hashes = [])
165 {
166 if ($_depth >= $this->maxDepth || \in_array(\spl_object_hash($object), $hashes, \true)) {
167 return $this->serializeValue($object);
168 }
169 $hashes[] = \spl_object_hash($object);
170 $serializedObject = [];
171 foreach ($object as $key => &$value) {
172 if (\is_object($value)) {
173 $serializedObject[$key] = $this->serializeObject($value, $_depth + 1, $hashes);
174 } else {
175 $serializedObject[$key] = $this->serializeRecursively($value, $_depth + 1);
176 }
177 }
178 return $serializedObject;
179 }
180 /**
181 * Serializes the given value to a string.
182 *
183 * @param string $value The value to serialize
184 */
185 protected function serializeString(string $value) : string
186 {
187 if ($value === '') {
188 return '';
189 }
190 // we always guarantee this is coerced, even if we can't detect encoding
191 if ($currentEncoding = \mb_detect_encoding($value, $this->mbDetectOrder)) {
192 $encoded = \mb_convert_encoding($value, 'UTF-8', $currentEncoding) ?: '<encoding error>';
193 } else {
194 $encoded = \mb_convert_encoding($value, 'UTF-8') ?: '<encoding error>';
195 }
196 if (\mb_strlen($encoded) > $this->options->getMaxValueLength()) {
197 $encoded = \mb_substr($encoded, 0, $this->options->getMaxValueLength() - 10, 'UTF-8') . ' {clipped}';
198 }
199 return $encoded;
200 }
201 /**
202 * @param mixed $value
203 *
204 * @return string|bool|float|int|null
205 */
206 protected function serializeValue($value)
207 {
208 if ($value === null || \is_bool($value) || \is_numeric($value)) {
209 return $value;
210 }
211 if ($value instanceof \UnitEnum) {
212 $reflection = new \ReflectionObject($value);
213 $enumValue = $reflection->getName() . '::' . $value->name;
214 if ($value instanceof \BackedEnum) {
215 return 'Enum ' . $enumValue . '(' . $value->value . ')';
216 }
217 return 'Enum ' . $enumValue;
218 }
219 if (\is_object($value)) {
220 $reflection = new \ReflectionObject($value);
221 $objectId = null;
222 if ($reflection->hasProperty('id') && ($idProperty = $reflection->getProperty('id'))->isPublic()) {
223 $objectId = $idProperty->getValue($value);
224 } elseif ($reflection->hasMethod('getId') && ($getIdMethod = $reflection->getMethod('getId'))->isPublic()) {
225 try {
226 $objectId = $getIdMethod->invoke($value);
227 } catch (\Throwable $e) {
228 // Do nothing on purpose
229 }
230 }
231 return 'Object ' . $reflection->getName() . (\is_scalar($objectId) ? '(#' . $objectId . ')' : '');
232 }
233 if (\is_resource($value)) {
234 return 'Resource ' . \get_resource_type($value);
235 }
236 try {
237 if (@\is_callable($value)) {
238 return $this->serializeCallable($value);
239 }
240 } catch (\Throwable $exception) {
241 // Do nothing on purpose
242 }
243 if (\is_array($value)) {
244 return 'Array of length ' . \count($value);
245 }
246 if (\is_string($value) || \is_object($value) && \method_exists($value, '__toString')) {
247 return $this->serializeString((string) $value);
248 }
249 return null;
250 }
251 private function formatDate(\DateTimeInterface $date) : string
252 {
253 $hasMicroseconds = $date->format('u') !== '000000';
254 $formatted = $hasMicroseconds ? $date->format('Y-m-d H:i:s.u') : $date->format('Y-m-d H:i:s');
255 $className = \get_class($date);
256 $timezone = $date->getTimezone();
257 if ($timezone && $timezone->getName() !== 'UTC') {
258 $formatted .= ' ' . $date->format('eP');
259 }
260 return "{$className}({$formatted})";
261 }
262 /**
263 * @param callable|mixed $callable
264 */
265 protected function serializeCallable($callable) : string
266 {
267 if (\is_string($callable)) {
268 return $callable;
269 }
270 if (!\is_callable($callable)) {
271 throw new \InvalidArgumentException(\sprintf('Expecting callable, got %s', \is_object($callable) ? \get_class($callable) : \gettype($callable)));
272 }
273 try {
274 if (\is_array($callable)) {
275 $reflection = new \ReflectionMethod($callable[0], $callable[1]);
276 $class = $reflection->getDeclaringClass();
277 } elseif ($callable instanceof \Closure) {
278 $reflection = new \ReflectionFunction($callable);
279 $class = null;
280 } elseif (\is_object($callable) && \method_exists($callable, '__invoke')) {
281 $reflection = new \ReflectionMethod($callable, '__invoke');
282 $class = $reflection->getDeclaringClass();
283 } else {
284 throw new \InvalidArgumentException('Unrecognized type of callable');
285 }
286 } catch (\ReflectionException $exception) {
287 return '{unserializable callable, reflection error}';
288 }
289 $callableType = $reflection->isClosure() ? 'Lambda ' : 'Callable ';
290 $callableReturnType = $reflection->getReturnType();
291 if ($callableReturnType instanceof \ReflectionNamedType) {
292 $callableType .= $callableReturnType->getName() . ' ';
293 }
294 if ($class) {
295 $callableType .= $class->getName() . '::';
296 }
297 return $callableType . $reflection->getName() . ' ' . $this->serializeCallableParameters($reflection);
298 }
299 private function serializeCallableParameters(\ReflectionFunctionAbstract $reflection) : string
300 {
301 $params = [];
302 foreach ($reflection->getParameters() as &$param) {
303 $reflectionType = $param->getType();
304 if ($reflectionType instanceof \ReflectionNamedType) {
305 $paramType = $reflectionType->getName();
306 } else {
307 $paramType = 'mixed';
308 }
309 if ($param->allowsNull()) {
310 $paramType .= '|null';
311 }
312 $paramName = ($param->isPassedByReference() ? '&' : '') . $param->getName();
313 if ($param->isOptional()) {
314 $paramName = '[' . $paramName . ']';
315 }
316 $params[] = $paramType . ' ' . $paramName;
317 }
318 return '[' . \implode('; ', $params) . ']';
319 }
320 public function getMbDetectOrder() : string
321 {
322 return $this->mbDetectOrder;
323 }
324 /**
325 * @return $this
326 */
327 public function setMbDetectOrder(string $mbDetectOrder) : self
328 {
329 $this->mbDetectOrder = $mbDetectOrder;
330 return $this;
331 }
332 public function setSerializeAllObjects(bool $value) : void
333 {
334 $this->serializeAllObjects = $value;
335 }
336 public function getSerializeAllObjects() : bool
337 {
338 return $this->serializeAllObjects;
339 }
340 }
341