1: <?php
2:
3: /*
4: * The MIT License (MIT)
5: *
6: * Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com)
7: *
8: * Permission is hereby granted, free of charge, to any person obtaining a copy of
9: * this software and associated documentation files (the "Software"), to deal in
10: * the Software without restriction, including without limitation the rights to
11: * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12: * the Software, and to permit persons to whom the Software is furnished to do so,
13: * subject to the following conditions:
14: *
15: * The above copyright notice and this permission notice shall be included in all
16: * copies or substantial portions of the Software.
17: *
18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20: * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21: * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22: * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23: * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24: */
25:
26: namespace Kint;
27:
28: use InvalidArgumentException;
29: use Kint\Object\BlobObject;
30: use ReflectionNamedType;
31: use ReflectionType;
32:
33: /**
34: * A collection of utility methods. Should all be static methods with no dependencies.
35: */
36: final class Utils
37: {
38: /**
39: * @codeCoverageIgnore
40: */
41: private function __construct()
42: {
43: }
44:
45: /**
46: * Turns a byte value into a human-readable representation.
47: *
48: * @param int $value Amount of bytes
49: *
50: * @return array Human readable value and unit
51: */
52: public static function getHumanReadableBytes($value)
53: {
54: static $unit = array('B', 'KB', 'MB', 'GB', 'TB');
55:
56: $i = \floor(\log($value, 1024));
57: $i = \min($i, 4); // Only go up to TB
58:
59: return array(
60: 'value' => (float) ($value / \pow(1024, $i)),
61: 'unit' => $unit[$i],
62: );
63: }
64:
65: public static function isSequential(array $array)
66: {
67: return \array_keys($array) === \range(0, \count($array) - 1);
68: }
69:
70: public static function composerGetExtras($key = 'kint')
71: {
72: $extras = array();
73:
74: if (0 === \strpos(KINT_DIR, 'phar://')) {
75: // Only run inside phar file, so skip for code coverage
76: return $extras; // @codeCoverageIgnore
77: }
78:
79: $folder = KINT_DIR.'/vendor';
80:
81: for ($i = 0; $i < 4; ++$i) {
82: $installed = $folder.'/composer/installed.json';
83:
84: if (\file_exists($installed) && \is_readable($installed)) {
85: $packages = \json_decode(\file_get_contents($installed), true);
86:
87: foreach ($packages as $package) {
88: if (isset($package['extra'][$key]) && \is_array($package['extra'][$key])) {
89: $extras = \array_replace($extras, $package['extra'][$key]);
90: }
91: }
92:
93: $folder = \dirname($folder);
94:
95: if (\file_exists($folder.'/composer.json') && \is_readable($folder.'/composer.json')) {
96: $composer = \json_decode(\file_get_contents($folder.'/composer.json'), true);
97:
98: if (isset($composer['extra'][$key]) && \is_array($composer['extra'][$key])) {
99: $extras = \array_replace($extras, $composer['extra'][$key]);
100: }
101: }
102:
103: break;
104: }
105:
106: $folder = \dirname($folder);
107: }
108:
109: return $extras;
110: }
111:
112: /**
113: * @codeCoverageIgnore
114: */
115: public static function composerSkipFlags()
116: {
117: $extras = self::composerGetExtras();
118:
119: if (!empty($extras['disable-facade']) && !\defined('KINT_SKIP_FACADE')) {
120: \define('KINT_SKIP_FACADE', true);
121: }
122:
123: if (!empty($extras['disable-helpers']) && !\defined('KINT_SKIP_HELPERS')) {
124: \define('KINT_SKIP_HELPERS', true);
125: }
126: }
127:
128: public static function isTrace(array $trace)
129: {
130: if (!self::isSequential($trace)) {
131: return false;
132: }
133:
134: static $bt_structure = array(
135: 'function' => 'string',
136: 'line' => 'integer',
137: 'file' => 'string',
138: 'class' => 'string',
139: 'object' => 'object',
140: 'type' => 'string',
141: 'args' => 'array',
142: );
143:
144: $file_found = false;
145:
146: foreach ($trace as $frame) {
147: if (!\is_array($frame) || !isset($frame['function'])) {
148: return false;
149: }
150:
151: foreach ($frame as $key => $val) {
152: if (!isset($bt_structure[$key])) {
153: return false;
154: }
155:
156: if (\gettype($val) !== $bt_structure[$key]) {
157: return false;
158: }
159:
160: if ('file' === $key) {
161: $file_found = true;
162: }
163: }
164: }
165:
166: return $file_found;
167: }
168:
169: public static function traceFrameIsListed(array $frame, array $matches)
170: {
171: if (isset($frame['class'])) {
172: $called = array(\strtolower($frame['class']), \strtolower($frame['function']));
173: } else {
174: $called = \strtolower($frame['function']);
175: }
176:
177: return \in_array($called, $matches, true);
178: }
179:
180: public static function normalizeAliases(array &$aliases)
181: {
182: static $name_regex = '[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*';
183:
184: foreach ($aliases as $index => &$alias) {
185: if (\is_array($alias) && 2 === \count($alias)) {
186: $alias = \array_values(\array_filter($alias, 'is_string'));
187:
188: if (2 === \count($alias) &&
189: \preg_match('/^'.$name_regex.'$/', $alias[1]) &&
190: \preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias[0])
191: ) {
192: $alias = array(
193: \strtolower(\ltrim($alias[0], '\\')),
194: \strtolower($alias[1]),
195: );
196: } else {
197: unset($aliases[$index]);
198: continue;
199: }
200: } elseif (\is_string($alias)) {
201: if (\preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias)) {
202: $alias = \explode('\\', \strtolower($alias));
203: $alias = \end($alias);
204: } else {
205: unset($aliases[$index]);
206: continue;
207: }
208: } else {
209: unset($aliases[$index]);
210: }
211: }
212:
213: $aliases = \array_values($aliases);
214: }
215:
216: public static function truncateString($input, $length = PHP_INT_MAX, $end = '...', $encoding = false)
217: {
218: $length = (int) $length;
219: $endlength = BlobObject::strlen($end);
220:
221: if ($endlength >= $length) {
222: throw new InvalidArgumentException('Can\'t truncate a string to '.$length.' characters if ending with string '.$endlength.' characters long');
223: }
224:
225: if (BlobObject::strlen($input, $encoding) > $length) {
226: return BlobObject::substr($input, 0, $length - $endlength, $encoding).$end;
227: }
228:
229: return $input;
230: }
231:
232: public static function getTypeString(ReflectionType $type)
233: {
234: if ($type instanceof ReflectionNamedType) {
235: return $type->getName();
236: }
237:
238: return (string) $type; // @codeCoverageIgnore
239: }
240: }
241: