Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Bar
  • BlueScreen
  • Debugger
  • DefaultBarPanel
  • Dumper
  • FireLogger
  • Helpers
  • Logger
  • OutputDebugger

Interfaces

  • IBarPanel
  • ILogger
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Tracy (https://tracy.nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Tracy;
  9: 
 10: 
 11: /**
 12:  * Rendering helpers for Debugger.
 13:  */
 14: class Helpers
 15: {
 16: 
 17:     /**
 18:      * Returns HTML link to editor.
 19:      * @return string
 20:      */
 21:     public static function editorLink($file, $line = null)
 22:     {
 23:         $file = strtr($origFile = $file, Debugger::$editorMapping);
 24:         if ($editor = self::editorUri($origFile, $line)) {
 25:             $file = strtr($file, '\\', '/');
 26:             if (preg_match('#(^[a-z]:)?/.{1,50}$#i', $file, $m) && strlen($file) > strlen($m[0])) {
 27:                 $file = '...' . $m[0];
 28:             }
 29:             $file = strtr($file, '/', DIRECTORY_SEPARATOR);
 30:             return self::formatHtml('<a href="%" title="%">%<b>%</b>%</a>',
 31:                 $editor,
 32:                 $file . ($line ? ":$line" : ''),
 33:                 rtrim(dirname($file), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR,
 34:                 basename($file),
 35:                 $line ? ":$line" : ''
 36:             );
 37:         } else {
 38:             return self::formatHtml('<span>%</span>', $file . ($line ? ":$line" : ''));
 39:         }
 40:     }
 41: 
 42: 
 43:     /**
 44:      * Returns link to editor.
 45:      * @return string|null
 46:      */
 47:     public static function editorUri($file, $line = null, $action = 'open', $search = null, $replace = null)
 48:     {
 49:         if (Debugger::$editor && $file && ($action === 'create' || is_file($file))) {
 50:             $file = strtr($file, '/', DIRECTORY_SEPARATOR);
 51:             $file = strtr($file, Debugger::$editorMapping);
 52:             return strtr(Debugger::$editor, [
 53:                 '%action' => $action,
 54:                 '%file' => rawurlencode($file),
 55:                 '%line' => $line ? (int) $line : 1,
 56:                 '%search' => rawurlencode($search),
 57:                 '%replace' => rawurlencode($replace),
 58:             ]);
 59:         }
 60:     }
 61: 
 62: 
 63:     public static function formatHtml($mask)
 64:     {
 65:         $args = func_get_args();
 66:         return preg_replace_callback('#%#', function () use (&$args, &$count) {
 67:             return Helpers::escapeHtml($args[++$count]);
 68:         }, $mask);
 69:     }
 70: 
 71: 
 72:     public static function escapeHtml($s)
 73:     {
 74:         return htmlspecialchars((string) $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
 75:     }
 76: 
 77: 
 78:     public static function findTrace(array $trace, $method, &$index = null)
 79:     {
 80:         $m = explode('::', $method);
 81:         foreach ($trace as $i => $item) {
 82:             if (
 83:                 isset($item['function'])
 84:                 && $item['function'] === end($m)
 85:                 && isset($item['class']) === isset($m[1])
 86:                 && (!isset($item['class']) || $m[0] === '*' || is_a($item['class'], $m[0], true))
 87:             ) {
 88:                 $index = $i;
 89:                 return $item;
 90:             }
 91:         }
 92:     }
 93: 
 94: 
 95:     /**
 96:      * @return string
 97:      */
 98:     public static function getClass($obj)
 99:     {
100:         return explode("\x00", get_class($obj))[0];
101:     }
102: 
103: 
104:     /** @internal */
105:     public static function fixStack($exception)
106:     {
107:         if (function_exists('xdebug_get_function_stack')) {
108:             $stack = [];
109:             foreach (array_slice(array_reverse(xdebug_get_function_stack()), 2, -1) as $row) {
110:                 $frame = [
111:                     'file' => $row['file'],
112:                     'line' => $row['line'],
113:                     'function' => isset($row['function']) ? $row['function'] : '*unknown*',
114:                     'args' => [],
115:                 ];
116:                 if (!empty($row['class'])) {
117:                     $frame['type'] = isset($row['type']) && $row['type'] === 'dynamic' ? '->' : '::';
118:                     $frame['class'] = $row['class'];
119:                 }
120:                 $stack[] = $frame;
121:             }
122:             $ref = new \ReflectionProperty('Exception', 'trace');
123:             $ref->setAccessible(true);
124:             $ref->setValue($exception, $stack);
125:         }
126:         return $exception;
127:     }
128: 
129: 
130:     /** @internal */
131:     public static function fixEncoding($s)
132:     {
133:         return htmlspecialchars_decode(htmlspecialchars($s, ENT_NOQUOTES | ENT_IGNORE, 'UTF-8'), ENT_NOQUOTES);
134:     }
135: 
136: 
137:     /** @internal */
138:     public static function errorTypeToString($type)
139:     {
140:         $types = [
141:             E_ERROR => 'Fatal Error',
142:             E_USER_ERROR => 'User Error',
143:             E_RECOVERABLE_ERROR => 'Recoverable Error',
144:             E_CORE_ERROR => 'Core Error',
145:             E_COMPILE_ERROR => 'Compile Error',
146:             E_PARSE => 'Parse Error',
147:             E_WARNING => 'Warning',
148:             E_CORE_WARNING => 'Core Warning',
149:             E_COMPILE_WARNING => 'Compile Warning',
150:             E_USER_WARNING => 'User Warning',
151:             E_NOTICE => 'Notice',
152:             E_USER_NOTICE => 'User Notice',
153:             E_STRICT => 'Strict standards',
154:             E_DEPRECATED => 'Deprecated',
155:             E_USER_DEPRECATED => 'User Deprecated',
156:         ];
157:         return isset($types[$type]) ? $types[$type] : 'Unknown error';
158:     }
159: 
160: 
161:     /** @internal */
162:     public static function getSource()
163:     {
164:         if (isset($_SERVER['REQUEST_URI'])) {
165:             return (!empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https://' : 'http://')
166:                 . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '')
167:                 . $_SERVER['REQUEST_URI'];
168:         } else {
169:             return 'CLI (PID: ' . getmypid() . ')'
170:                 . (empty($_SERVER['argv']) ? '' : ': ' . implode(' ', $_SERVER['argv']));
171:         }
172:     }
173: 
174: 
175:     /** @internal */
176:     public static function improveException($e)
177:     {
178:         $message = $e->getMessage();
179:         if (!$e instanceof \Error && !$e instanceof \ErrorException) {
180:             // do nothing
181:         } elseif (preg_match('#^Call to undefined function (\S+\\\\)?(\w+)\(#', $message, $m)) {
182:             $funcs = array_merge(get_defined_functions()['internal'], get_defined_functions()['user']);
183:             $hint = self::getSuggestion($funcs, $m[1] . $m[2]) ?: self::getSuggestion($funcs, $m[2]);
184:             $message = "Call to undefined function $m[2](), did you mean $hint()?";
185:             $replace = ["$m[2](", "$hint("];
186: 
187:         } elseif (preg_match('#^Call to undefined method ([\w\\\\]+)::(\w+)#', $message, $m)) {
188:             $hint = self::getSuggestion(get_class_methods($m[1]), $m[2]);
189:             $message .= ", did you mean $hint()?";
190:             $replace = ["$m[2](", "$hint("];
191: 
192:         } elseif (preg_match('#^Undefined variable: (\w+)#', $message, $m) && !empty($e->context)) {
193:             $hint = self::getSuggestion(array_keys($e->context), $m[1]);
194:             $message = "Undefined variable $$m[1], did you mean $$hint?";
195:             $replace = ["$$m[1]", "$$hint"];
196: 
197:         } elseif (preg_match('#^Undefined property: ([\w\\\\]+)::\$(\w+)#', $message, $m)) {
198:             $rc = new \ReflectionClass($m[1]);
199:             $items = array_diff($rc->getProperties(\ReflectionProperty::IS_PUBLIC), $rc->getProperties(\ReflectionProperty::IS_STATIC));
200:             $hint = self::getSuggestion($items, $m[2]);
201:             $message .= ", did you mean $$hint?";
202:             $replace = ["->$m[2]", "->$hint"];
203: 
204:         } elseif (preg_match('#^Access to undeclared static property: ([\w\\\\]+)::\$(\w+)#', $message, $m)) {
205:             $rc = new \ReflectionClass($m[1]);
206:             $items = array_intersect($rc->getProperties(\ReflectionProperty::IS_PUBLIC), $rc->getProperties(\ReflectionProperty::IS_STATIC));
207:             $hint = self::getSuggestion($items, $m[2]);
208:             $message .= ", did you mean $$hint?";
209:             $replace = ["::$$m[2]", "::$$hint"];
210:         }
211: 
212:         if (isset($hint)) {
213:             $ref = new \ReflectionProperty($e, 'message');
214:             $ref->setAccessible(true);
215:             $ref->setValue($e, $message);
216:             $e->tracyAction = [
217:                 'link' => self::editorUri($e->getFile(), $e->getLine(), 'fix', $replace[0], $replace[1]),
218:                 'label' => 'fix it',
219:             ];
220:         }
221:     }
222: 
223: 
224:     /**
225:      * Finds the best suggestion.
226:      * @return string|null
227:      * @internal
228:      */
229:     public static function getSuggestion(array $items, $value)
230:     {
231:         $best = null;
232:         $min = (strlen($value) / 4 + 1) * 10 + .1;
233:         foreach (array_unique($items, SORT_REGULAR) as $item) {
234:             $item = is_object($item) ? $item->getName() : $item;
235:             if (($len = levenshtein($item, $value, 10, 11, 10)) > 0 && $len < $min) {
236:                 $min = $len;
237:                 $best = $item;
238:             }
239:         }
240:         return $best;
241:     }
242: 
243: 
244:     /** @internal */
245:     public static function isHtmlMode()
246:     {
247:         return empty($_SERVER['HTTP_X_REQUESTED_WITH']) && empty($_SERVER['HTTP_X_TRACY_AJAX'])
248:             && PHP_SAPI !== 'cli'
249:             && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()));
250:     }
251: 
252: 
253:     /** @internal */
254:     public static function isAjax()
255:     {
256:         return isset($_SERVER['HTTP_X_TRACY_AJAX']) && preg_match('#^\w{10}\z#', $_SERVER['HTTP_X_TRACY_AJAX']);
257:     }
258: 
259: 
260:     /** @internal */
261:     public static function getNonce()
262:     {
263:         return preg_match('#^Content-Security-Policy(?:-Report-Only)?:.*\sscript-src\s+(?:[^;]+\s)?\'nonce-([\w+/]+=*)\'#mi', implode("\n", headers_list()), $m)
264:             ? $m[1]
265:             : null;
266:     }
267: }
268: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0