These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Provides a number of helper functions for the audit component |
||
4 | */ |
||
5 | |||
6 | namespace bedezign\yii2\audit\components; |
||
7 | |||
8 | use bedezign\yii2\audit\Audit; |
||
9 | use yii\helpers\ArrayHelper; |
||
10 | use yii\helpers\VarDumper; |
||
11 | |||
12 | /** |
||
13 | * Helper |
||
14 | * @package bedezign\yii2\audit\components |
||
15 | */ |
||
16 | class Helper extends \yii\base\Object |
||
0 ignored issues
–
show
|
|||
17 | { |
||
18 | /** |
||
19 | * Convert the given value into a gzip compressed blob so it can be stored in the database |
||
20 | * @param mixed $data |
||
21 | * @param bool $compact true to call the {@link compact()} function first |
||
22 | * @return string binary blob of data |
||
23 | */ |
||
24 | 90 | public static function serialize($data, $compact = true) |
|
25 | { |
||
26 | if ($compact) |
||
27 | 90 | $data = self::compact($data); |
|
28 | |||
29 | 90 | $data = serialize($data); |
|
30 | 90 | $data = self::compress($data); |
|
31 | |||
32 | 90 | return $data; |
|
33 | } |
||
34 | |||
35 | /** |
||
36 | * Re-inflates and unserializes a blob of compressed data |
||
37 | * @param string $data |
||
38 | * @return mixed false if an error occurred |
||
39 | */ |
||
40 | 96 | public static function unserialize($data) |
|
41 | { |
||
42 | 96 | if (is_resource($data)) |
|
43 | // For some databases (like Postgres) binary columns return as a resource, fetch the content first |
||
44 | 96 | $data = stream_get_contents($data, -1, 0); |
|
45 | |||
46 | 96 | $originalData = $data; |
|
47 | 96 | $data = self::uncompress($data); |
|
48 | |||
49 | 96 | if ($data === false) |
|
50 | 96 | $data = $originalData; |
|
51 | |||
52 | 96 | $data = @unserialize($data); |
|
53 | 96 | if ($data === false) |
|
54 | 96 | $data = $originalData; |
|
55 | |||
56 | 96 | return $data; |
|
57 | } |
||
58 | |||
59 | /** |
||
60 | * Compress |
||
61 | * @param mixed $data |
||
62 | * @return string binary blob of data |
||
63 | */ |
||
64 | 90 | public static function compress($data) |
|
65 | { |
||
66 | 90 | if (Audit::getInstance()->compressData) |
|
67 | 90 | $data = gzcompress($data); |
|
68 | 90 | return $data; |
|
69 | } |
||
70 | |||
71 | /** |
||
72 | * Compress |
||
73 | * @param mixed $data |
||
74 | * @return string binary blob of data |
||
75 | */ |
||
76 | 96 | public static function uncompress($data) |
|
77 | { |
||
78 | 96 | $originalData = $data; |
|
79 | 96 | $data = @gzuncompress($data); |
|
80 | 96 | return $data ?: $originalData; |
|
81 | } |
||
82 | |||
83 | /** |
||
84 | * Enumerate an array and get rid of the values that would exceed the $threshold size when serialized |
||
85 | * @param array $data Non-array data will be converted to an array |
||
86 | * @param bool $simplify If true, replace single valued arrays by just its value. |
||
87 | * @param int $threshold serialized size to use as maximum |
||
88 | * @return array |
||
89 | */ |
||
90 | 27 | public static function compact($data, $simplify = false, $threshold = 512) |
|
91 | 27 | { |
|
92 | 9 | $data = ArrayHelper::toArray($data); |
|
93 | if ($simplify) |
||
94 | 3 | array_walk($data, function (&$value) { |
|
95 | 3 | if (is_array($value) && count($value) == 1) $value = reset($value); |
|
96 | 3 | }); |
|
97 | |||
98 | 9 | $tooBig = []; |
|
99 | 9 | foreach ($data as $index => $value) |
|
100 | 9 | if (strlen(serialize($value)) > $threshold) |
|
101 | 9 | $tooBig[] = $index; |
|
102 | |||
103 | 9 | if (count($tooBig)) { |
|
104 | 3 | $data = array_diff_key($data, array_flip($tooBig)); |
|
105 | 3 | $data['__removed'] = $tooBig; |
|
106 | 3 | } |
|
107 | |||
108 | 9 | return $data; |
|
109 | } |
||
110 | |||
111 | /** |
||
112 | * Generate a stacktrace and clean it (usually for regular errors) |
||
113 | * @param int $skip Amount of entries to skip (usually 1 or 2). 2 is assuming this helper function and your logging function |
||
114 | * @return array |
||
115 | */ |
||
116 | public static function generateTrace($skip = 2) |
||
117 | { |
||
118 | $trace = debug_backtrace(); |
||
119 | array_pop($trace); // remove the last trace since it would be the entry script, not very useful |
||
120 | if ($skip > 0) |
||
121 | $trace = array_slice($trace, $skip); |
||
122 | return self::cleanupTrace($trace); |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Normalize a stack trace so that all entries have the same keys and cleanup the arguments (removes anything that |
||
127 | * cannot be serialized). |
||
128 | * @param array $trace |
||
129 | * @return array |
||
130 | */ |
||
131 | 33 | public static function cleanupTrace($trace) |
|
132 | { |
||
133 | 33 | if (!is_array($trace)) |
|
134 | 33 | return []; |
|
135 | |||
136 | 33 | foreach ($trace as $n => $call) { |
|
137 | 27 | $call['file'] = isset($call['file']) ? $call['file'] : 'unknown'; |
|
138 | 27 | $call['line'] = isset($call['line']) ? $call['line'] : 0; |
|
139 | 27 | $call['function'] = isset($call['function']) ? $call['function'] : 'unknown'; |
|
140 | 27 | $call['file'] = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $call['file']); |
|
141 | |||
142 | // XDebug |
||
143 | 27 | if (isset($call['params'])) unset($call['params']); |
|
144 | |||
145 | // Trace entry contains the class instance, also compact and include this |
||
146 | 27 | if (isset($call['object'])) |
|
147 | 27 | $call['object'] = current(self::cleanupTraceArguments([$call['object']])); |
|
148 | |||
149 | 27 | if (isset($call['args'])) |
|
150 | 27 | $call['args'] = self::cleanupTraceArguments($call['args']); |
|
151 | |||
152 | 27 | $trace[$n] = $call; |
|
153 | 33 | } |
|
154 | |||
155 | 33 | return $trace; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * Cleans up the given data so it can be serialized |
||
160 | * @param $args |
||
161 | * @param int $recurseDepth Amount of recursion cycles before we start replacing data with "Array" etc |
||
162 | * @return mixed |
||
163 | */ |
||
164 | 27 | public static function cleanupTraceArguments($args, $recurseDepth = 3) |
|
165 | { |
||
166 | 27 | foreach ($args as $name => $value) { |
|
167 | 27 | if (is_object($value)) { |
|
168 | 27 | $class = get_class($value); |
|
169 | // By default we just mention the object type |
||
170 | 27 | $args[$name] = 'Object(' . $class . ')'; |
|
171 | |||
172 | 27 | if ($recurseDepth > 0) { |
|
173 | // Make sure to limit the toArray to non recursive, it's much to easy to get stuck in an infinite loop |
||
174 | 27 | $object = self::cleanupTraceArguments(ArrayHelper::toArray($value, [], false), $recurseDepth - 1); |
|
175 | 27 | $object['__class'] = $class; |
|
176 | 27 | $args[$name] = $object; |
|
177 | 27 | } |
|
178 | 27 | } else if (is_array($value)) { |
|
179 | 27 | if ($recurseDepth > 0) |
|
180 | 27 | $args[$name] = self::cleanupTraceArguments($value, $recurseDepth - 1); |
|
181 | else |
||
182 | 21 | $args[$name] = 'Array'; |
|
183 | 27 | } |
|
184 | 27 | } |
|
185 | 27 | return $args; |
|
186 | } |
||
187 | |||
188 | /** |
||
189 | * Hash a long string to a short string. |
||
190 | * @link http://au1.php.net/crc32#111931 |
||
191 | * |
||
192 | * @param $data |
||
193 | * @return string |
||
194 | */ |
||
195 | 33 | public static function hash($data) |
|
196 | { |
||
197 | 33 | static $map = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
|
198 | 33 | $hash = bcadd(sprintf('%u', crc32($data)), 0x100000000); |
|
199 | 33 | $str = ''; |
|
200 | do { |
||
201 | 33 | $str = $map[bcmod($hash, 62)] . $str; |
|
202 | 33 | $hash = bcdiv($hash, 62); |
|
203 | 33 | } while ($hash >= 1); |
|
204 | 33 | return $str; |
|
205 | } |
||
206 | |||
207 | /** |
||
208 | * If the data resembles a query string it will be returned as a formatted variable for output |
||
209 | * @param $data |
||
210 | * @return null|string |
||
211 | */ |
||
212 | 9 | public static function formatAsQuery($data) |
|
213 | { |
||
214 | 9 | $data = rawurldecode($data); |
|
215 | 9 | if (!preg_match('/^([\w\d\-\[\]]+(=[^&]*)?(&[\w\d\-\[\]]+(=[^&]*)?)*)?$/', $data)) |
|
216 | 9 | return null; |
|
217 | |||
218 | 3 | $result = []; |
|
219 | 3 | parse_str($data, $result); |
|
220 | 3 | return VarDumper::dumpAsString($result, 15); |
|
221 | } |
||
222 | |||
223 | /** |
||
224 | * If the data contains JSON it will be returned as a pretty printable string |
||
225 | * @param $data |
||
226 | * @return null|string |
||
227 | */ |
||
228 | 9 | public static function formatAsJSON($data) |
|
229 | { |
||
230 | 9 | $decoded = @json_decode($data); |
|
231 | 9 | return $decoded ? json_encode($decoded, JSON_PRETTY_PRINT) : null; |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * If the data contains XML it will be returned as a pretty printable string |
||
236 | * @param $data |
||
237 | * @return null|string |
||
238 | */ |
||
239 | 6 | public static function formatAsXML($data) |
|
240 | { |
||
241 | 6 | $doc = new \DOMDocument('1.0'); |
|
242 | 6 | $doc->preserveWhiteSpace = false; |
|
243 | 6 | $doc->formatOutput = true; |
|
244 | 6 | if (@$doc->loadXML($data)) |
|
245 | 6 | return htmlentities($doc->saveXML(), ENT_COMPAT, 'UTF-8'); |
|
246 | 3 | return null; |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * If the data contains HTML it will be returned as a pretty printable string |
||
251 | * @param $data |
||
252 | * @return null|string |
||
253 | */ |
||
254 | 6 | public static function formatAsHTML($data) |
|
255 | { |
||
256 | 6 | if ($data == strip_tags($data) || strtolower(substr(ltrim($data), 0, 5)) == '<?xml') |
|
257 | 6 | return null; |
|
258 | |||
259 | 3 | $doc = new \DOMDocument('1.0'); |
|
260 | 3 | $doc->preserveWhiteSpace = false; |
|
261 | 3 | $doc->formatOutput = true; |
|
262 | 3 | if (@$doc->loadHTML($data)) |
|
263 | 3 | return htmlentities($doc->saveHTML(), ENT_COMPAT, 'UTF-8'); |
|
264 | return null; |
||
265 | } |
||
266 | } |
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.