PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.22
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.22
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 1.10.1 All 168 releases
woocommerce-pos / vendor_prefixed / sentry / sentry / src / FrameBuilder.php

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

200 lines 9.0 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 namespace WCPOS\Vendor\Sentry;
5
6 use WCPOS\Vendor\Sentry\Serializer\RepresentationSerializerInterface;
7 use WCPOS\Vendor\Sentry\Util\PrefixStripper;
8 /**
9 * This class builds a {@see Frame} object out of a backtrace's raw frame.
10 *
11 * @internal
12 *
13 * @phpstan-type StacktraceFrame array{
14 * function?: string,
15 * line?: int,
16 * file?: string,
17 * class?: class-string,
18 * type?: string,
19 * args?: mixed[]
20 * }
21 */
22 final class FrameBuilder
23 {
24 use PrefixStripper;
25 /**
26 * @var Options The SDK client options
27 */
28 private $options;
29 /**
30 * @var RepresentationSerializerInterface The representation serializer
31 */
32 private $representationSerializer;
33 /**
34 * Constructor.
35 *
36 * @param Options $options The SDK client options
37 * @param RepresentationSerializerInterface $representationSerializer The representation serializer
38 */
39 public function __construct(Options $options, RepresentationSerializerInterface $representationSerializer)
40 {
41 $this->options = $options;
42 $this->representationSerializer = $representationSerializer;
43 }
44 /**
45 * Builds a {@see Frame} object from the given backtrace's raw frame.
46 *
47 * @param string $file The file where the frame originated
48 * @param int $line The line at which the frame originated
49 * @param array<string, mixed> $backtraceFrame The raw frame
50 *
51 * @phpstan-param StacktraceFrame $backtraceFrame
52 */
53 public function buildFromBacktraceFrame(string $file, int $line, array $backtraceFrame) : Frame
54 {
55 // The filename can be in any of these formats:
56 // - </path/to/filename>
57 // - </path/to/filename>(<line number>) : eval()'d code
58 // - </path/to/filename>(<line number>) : runtime-created function
59 if (\preg_match('/^(.*)\\((\\d+)\\) : (?:eval\\(\\)\'d code|runtime-created function)$/', $file, $matches)) {
60 $file = $matches[1];
61 $line = (int) $matches[2];
62 }
63 $functionName = null;
64 $rawFunctionName = null;
65 $strippedFilePath = $this->stripPrefixFromFilePath($this->options, $file);
66 if (isset($backtraceFrame['class']) && isset($backtraceFrame['function'])) {
67 $functionName = $backtraceFrame['class'];
68 // Skip if no prefixes are set
69 if ($this->options->getPrefixes()) {
70 $prefixStrippedFunctionName = \preg_replace_callback('/@anonymous\\x00([^:]+)(:.*)?/', function (array $matches) {
71 return "@anonymous\x00" . $this->stripPrefixFromFilePath($this->options, $matches[1]) . ($matches[2] ?? '');
72 }, $functionName);
73 if ($prefixStrippedFunctionName) {
74 $functionName = $prefixStrippedFunctionName;
75 }
76 }
77 $rawFunctionName = \sprintf('%s::%s', $backtraceFrame['class'], $backtraceFrame['function']);
78 $functionName = \sprintf('%s::%s', \preg_replace('/(?::\\d+\\$|0x)[a-fA-F0-9]+$/', '', $functionName), $backtraceFrame['function']);
79 } elseif (isset($backtraceFrame['function'])) {
80 $functionName = $backtraceFrame['function'];
81 }
82 // Starting with PHP 8.4 a closure function call is reported as "{closure:filename:line}" instead of just "{closure}", properly strip the prefixes from that format
83 if (\PHP_VERSION_ID >= 80400 && $functionName !== null && $this->options->getPrefixes()) {
84 $prefixStrippedFunctionName = \preg_replace_callback('/^\\{closure:(.*?):(\\d+)}$/', function (array $matches) {
85 return '{closure:' . $this->stripPrefixFromFilePath($this->options, $matches[1]) . ':' . $matches[2] . '}';
86 }, $functionName);
87 if ($prefixStrippedFunctionName) {
88 $functionName = $prefixStrippedFunctionName;
89 }
90 }
91 return new Frame($functionName, $strippedFilePath, $line, $rawFunctionName, $file !== Frame::INTERNAL_FRAME_FILENAME ? $file : null, $this->getFunctionArguments($backtraceFrame), $this->isFrameInApp($file, $functionName));
92 }
93 /**
94 * Checks whether a certain frame should be marked as "in app" or not.
95 *
96 * @param string $file The file to check
97 * @param string|null $functionName The name of the function
98 */
99 private function isFrameInApp(string $file, ?string $functionName) : bool
100 {
101 if ($file === Frame::INTERNAL_FRAME_FILENAME) {
102 return \false;
103 }
104 if ($functionName !== null && \substr($functionName, 0, \strlen('WCPOS\\Vendor\\Sentry\\')) === 'WCPOS\\Vendor\\Sentry\\') {
105 return \false;
106 }
107 $excludedAppPaths = $this->options->getInAppExcludedPaths();
108 $includedAppPaths = $this->options->getInAppIncludedPaths();
109 if ($excludedAppPaths === [] && $includedAppPaths === []) {
110 return \true;
111 }
112 $absoluteFilePath = @\realpath($file) ?: $file;
113 $isInApp = \true;
114 foreach ($excludedAppPaths as $excludedAppPath) {
115 if (\strncmp($absoluteFilePath, $excludedAppPath, \strlen($excludedAppPath)) === 0) {
116 $isInApp = \false;
117 break;
118 }
119 }
120 foreach ($includedAppPaths as $includedAppPath) {
121 if (\strncmp($absoluteFilePath, $includedAppPath, \strlen($includedAppPath)) === 0) {
122 $isInApp = \true;
123 break;
124 }
125 }
126 return $isInApp;
127 }
128 /**
129 * Gets the arguments of the function called in the given frame.
130 *
131 * @param array<string, mixed> $backtraceFrame The frame data
132 *
133 * @phpstan-param StacktraceFrame $backtraceFrame
134 *
135 * @return array<string, mixed>
136 */
137 private function getFunctionArguments(array $backtraceFrame) : array
138 {
139 if (!isset($backtraceFrame['function'], $backtraceFrame['args'])) {
140 return [];
141 }
142 $reflectionFunction = null;
143 try {
144 if (isset($backtraceFrame['class'])) {
145 if (\method_exists($backtraceFrame['class'], $backtraceFrame['function'])) {
146 $reflectionFunction = new \ReflectionMethod($backtraceFrame['class'], $backtraceFrame['function']);
147 } elseif (isset($backtraceFrame['type']) && $backtraceFrame['type'] === '::') {
148 $reflectionFunction = new \ReflectionMethod($backtraceFrame['class'], '__callStatic');
149 } else {
150 $reflectionFunction = new \ReflectionMethod($backtraceFrame['class'], '__call');
151 }
152 } elseif ($backtraceFrame['function'] !== '__lambda_func' && !\str_starts_with($backtraceFrame['function'], '{closure') && \function_exists($backtraceFrame['function'])) {
153 $reflectionFunction = new \ReflectionFunction($backtraceFrame['function']);
154 }
155 } catch (\ReflectionException $e) {
156 // Reflection failed, we do nothing instead
157 }
158 $argumentValues = [];
159 if ($reflectionFunction !== null) {
160 $argumentValues = $this->getFunctionArgumentValues($reflectionFunction, $backtraceFrame['args']);
161 } else {
162 foreach ($backtraceFrame['args'] as $parameterPosition => $parameterValue) {
163 $argumentValues['param' . $parameterPosition] = $parameterValue;
164 }
165 }
166 foreach ($argumentValues as $argumentName => $argumentValue) {
167 $argumentValues[$argumentName] = $this->representationSerializer->representationSerialize($argumentValue);
168 }
169 return $argumentValues;
170 }
171 /**
172 * Gets an hashmap indexed by argument name containing all the arguments
173 * passed to the function called in the given frame of the stacktrace.
174 *
175 * @param \ReflectionFunctionAbstract $reflectionFunction A reflection object
176 * @param mixed[] $backtraceFrameArgs The arguments of the frame
177 *
178 * @return array<string, mixed>
179 */
180 private function getFunctionArgumentValues(\ReflectionFunctionAbstract $reflectionFunction, array $backtraceFrameArgs) : array
181 {
182 $argumentValues = [];
183 foreach ($reflectionFunction->getParameters() as $reflectionParameter) {
184 $parameterPosition = $reflectionParameter->getPosition();
185 if ($reflectionParameter->isVariadic()) {
186 // For variadic parameters, collect all remaining arguments into an array
187 $variadicArgs = \array_slice($backtraceFrameArgs, $parameterPosition);
188 $argumentValues[$reflectionParameter->getName()] = \array_values($variadicArgs);
189 // Variadic parameter is always the last one, so we can break
190 break;
191 }
192 if (!\array_key_exists($parameterPosition, $backtraceFrameArgs)) {
193 continue;
194 }
195 $argumentValues[$reflectionParameter->getName()] = $backtraceFrameArgs[$parameterPosition];
196 }
197 return $argumentValues;
198 }
199 }
200