5use Ubiquity\controllers\admin\popo\ComposerDependency;
14use Ubiquity\utils\base\UArray;
27 const CONTEXT_VARIABLES = [
44 private static $variables = [];
49 public static function start(&$config,
int $level = E_ALL) {
50 self::setErrorLevel($level);
52 $config[
'onError'] =
function ($code, $message =
null, $controllerInstance =
null) {
56 throw new \Exception($message);
64 \set_exception_handler(
function (\Throwable $ex) {
65 self::showException($ex);
75 public static function setErrorLevel(
int $level = E_ALL) {
76 \error_reporting($level);
78 \ini_set(
'display_errors',
'1');
82 public static function _error_handler($buffer) {
83 $e = \error_get_last();
85 if ($e[
'file'] !=
'xdebug://debug-eval' && ! UResponse::isJSON()) {
87 $code = self::getFileContent($file);
88 $error = $e[
'message'];
89 $type = TypeError::asString($e[
'type']);
91 $message = self::loadView(
'error', [
101 case E_COMPILE_ERROR:
103 return self::getErrorFromValues($file, $line, $error, $type,
'',
false);
106 return self::wrapResponse(\str_replace($e[
'message'],
"", $buffer) . $message);
109 return self::wrapResponse(\str_replace($e[
'message'] ??
'',
"", $buffer));
115 public static function showException(\Throwable $e) {
116 $file = $e->getFile();
117 $line = $e->getLine();
118 $traces = $e->getTrace();
119 echo self::getErrorFromValues($file, $line, $e->getMessage(), $e, self::showTraces($traces),
true);
122 private static function showTraces($traces) {
123 self::$variables = [];
125 foreach ($traces as $index => $trace) {
126 $tracesContent .= self::showTrace($trace, $index);
128 if ($tracesContent !=
null) {
129 return self::loadView(
'traces', [
130 'content' => $tracesContent,
131 'variables' => json_encode(self::$variables),
132 'count' => \count($traces)
138 private static function getGlobales($variables) {
140 foreach (self::CONTEXT_VARIABLES[
'globals'] as $k) {
141 $result[$k] = $variables[$k];
146 private static function getLocales() {
149 $ctrl = Startup::getController();
150 $variables[
'Request'][
'controller'] = $ctrl;
152 if (! \class_exists($ctrl)) {
153 $errors[
'Request'][
'controller'] = self::errorFlag(
"Controller $ctrl does not exist!");
155 $action = Startup::getAction();
156 if (isset($action)) {
157 $variables[
'Request'][
'action'] = $action;
158 if (! \method_exists($ctrl, $action)) {
159 $errors[
'Request'][
'action'] = self::errorFlag(
"Method $action does not exist on Controller $ctrl!");
161 $variables[
'Request'][
'params'] = Startup::getActionParams();
162 $variables[
'Request'][
'method'] = URequest::getMethod();
163 $path = Framework::getUrl();
164 $variables[
'Request'][
'url'] = $path;
165 $route = Router::getRouteInfo($path);
166 if ($route ===
false) {
167 $errors[
'Route'] = self::errorFlag(
"No route found for the url $path",
'exclamation circle orange');
169 $variables[
'Route'] = $route;
172 $variables[
'Application'][
'cacheSystem'] = Framework::getCacheSystem();
173 $variables[
'Application'][
'AnnotationsEngine'] = Framework::getAnnotationsEngine();
174 $variables[
'Application'][
'applicationDir'] = Startup::getApplicationDir();
175 $variables[
'Application'][
'Ubiquity-version'] = Framework::getVersion();
176 $variables[
'Config'] = Startup::$config;
177 $variables[
'system'][
'php'] = \phpversion();
178 $variables[
'system'][
'os'] = \php_uname();
179 $variables[
'system'][
'extensions'] = \implode(
', ', \get_loaded_extensions());
181 'variables' => $variables,
186 private static function displayVar($variable) {
187 if (! \is_string($variable) && ! \is_array($variable) && \is_callable($variable)) {
188 return UIntrospection::closure_dump($variable);
190 if (\is_object($variable)) {
191 return \get_class($variable) .
'@' . \spl_object_hash($variable);
193 if (! self::isRecursive($variable)) {
194 return \var_export($variable,
true);
196 return 'Recursive array!';
199 private static function isRecursive($array) {
200 $dump = \print_r($array,
true);
201 return \strpos($dump,
'*RECURSION*') !==
false;
204 private static function errorFlag($message, $type =
'exclamation triangle red') {
205 return " <i class='ui $type icon var_error' data-content='$message'></i>";
208 private static function showAllVariables() {
209 $l = self::getLocales();
210 $g = self::getGlobales($GLOBALS);
211 $locales = self::showVariables($l[
'variables'], $l[
'errors']);
212 $globales = self::showVariables($g);
213 return self::loadView(
'all_variables', compact(
'locales',
'globales'));
216 private static function showVariables($variables, $errors = []) {
217 $keys = \array_keys($variables);
219 $variables_elements =
'';
220 foreach ($keys as $i => $k) {
222 $v = $variables[$k] ??
'';
224 $error = $errors[$k] ?? [];
225 $ve = self::showVariable($k, $v, $error, 1);
227 $error = $errors[$k] ??
'';
228 $ve =
"<span class='ui label'><pre>" . self::displayVar($v) .
"</pre>$error</span>";
231 $first_var =
"<div class='variable'>$ve</div>";
234 $names .=
"<a class='item display_var $active' data-id='$k'>$k</a>";
235 $variables_elements .=
"<div id='ve-$k' class='variable'>$ve</div>";
237 return self::loadView(
'menu_variables', compact(
'names',
'variables_elements',
'first_var'));
240 private static function showVariable($name, array $variables, array $errors = [], $level = 1) {
242 $count = \count($variables);
244 foreach ($variables as $k => $v) {
245 if ($v != $variables) {
248 $error = $errors[$k] ?? [];
249 $v = self::showVariable($k, $v, $error, $level + 1);
251 $error = $errors[$k] ??
'';
252 $v =
'<span class="ui label"><pre>' . self::displayVar($v) .
"</pre>$error</span>";
254 $values .=
"<tr><td><b>$k</b></td><td>" . $v .
"</td></tr>";
257 return self::loadView(
'variable', [
259 'variables' => $values,
264 return '<span class="ui label">empty</span>';
267 private static function showTrace($trace, $index) {
268 $callFunction = $trace[
'function'] ??
'';
270 $line = $trace[
'line'] ?? 0;
271 $callClass = $trace[
'class'] ??
'no class';
272 $args = $trace[
'args'] ?? [];
273 $file = $trace[
'file'] ??
'no file';
274 $attr = UString::cleanAttribute($callClass .
"." . $callFunction);
275 self::$variables[$attr] = [];
276 if ($file !=
null && \file_exists($file)) {
277 $class = ClassUtils::getClassFullNameFromFile($file);
278 if ($class !=
null && $class !=
'\\' && (\class_exists($class) || \trait_exists($class))) {
279 $method = UIntrospection::getMethodAtLine($class, $line);
280 if ($callClass !==
'no class' && \method_exists($callClass, $callFunction)) {
281 $callMethod = new \ReflectionMethod($callClass, $callFunction);
283 if ($callMethod !=
null) {
284 $code = UIntrospection::getMethodCode($method, file($trace[
'file']));
286 $attributes = $callMethod->getParameters();
287 $effectiveArguments = self::getCallbackArguments($file, $line, $callFunction);
288 foreach ($attributes as $i => $param) {
289 $argValue = $args[$i] ??
'';
290 $arg = $effectiveArguments[$i] ?? (
'$' . $param->getName());
291 self::$variables[$attr][
'$' . $param->getName()] = [
292 'name' => $effectiveArguments[$i] ??
'',
293 'value' => self::displayVar($argValue)
295 $code = \preg_replace(
'#(\W*)(' . \preg_quote($arg) .
')(\W+)#',
'$1<mark>$2</mark>$3', $code);
297 $start = $method->getStartLine();
298 $countParams = count(self::$variables[$attr] ?? []);
300 if ($countParams > 0) {
301 $parameters = self::loadView(
'parameters', [
302 'count' => $countParams,
303 'variables' => self::getMethodParametersTable($attr)
306 return self::loadView(
'trace', [
307 'in' => $method->getName(),
308 'function' => $callFunction,
315 'parameters' => $parameters,
320 $code = self::getFileContent($file);
322 return self::loadView(
'trace', [
324 'function' => $callFunction,
338 private static function getCallbackArguments($file, $lineNumber, $callbackName) {
339 $fileContent = \file($file);
340 return UIntrospection::getMethodEffectiveParameters(
'<?php ' . $fileContent[$lineNumber - 1], $callbackName);
343 private static function getMethodParametersTable($functionName) {
345 if (isset(self::$variables[$functionName]) && \is_array(self::$variables[$functionName])) {
346 foreach (self::$variables[$functionName] as $name => $value) {
347 $res .=
"<tr><td><b>$name</b></td><td><pre>" . $value[
'value'] .
"</pre></td></tr>";
353 private static function getErrorFromValues($file, $line, $errorMessage, $errorType, $traces =
'', $introspect =
true) {
354 \restore_error_handler();
355 \restore_exception_handler();
357 $vars = self::showAllVariables();
358 $controller_action = \basename($file);
360 $class = ClassUtils::getClassFullNameFromFile($file,
true);
361 if ($class !==
null) {
362 $controller_action = $class;
363 $method = UIntrospection::getMethodAtLine($class, $line);
364 if ($method !=
null) {
365 $start = $method->getStartLine();
366 $code = UIntrospection::getMethodCode($method, file($file));
367 $controller_action .=
'::' . $method->getName();
373 $code = self::getFileContent($file);
375 $type = TypeError::asString($errorType);
376 $message = self::loadView(
'error', [
378 'error' => $errorMessage,
385 'controller_action' => $controller_action
387 return self::wrapResponse($message);
390 private static function wrapResponse($content) {
391 return self::getHeader() . $content . self::getFooter();
394 private static function getHeader() {
395 return '<div class="ui container">';
398 private static function getFooter() {
399 return '</div>' .
'<script type="text/javascript">' . \file_get_contents(__DIR__ .
'/js/loader.js') .
'</script>';
402 private static function getFileContent($file) {
403 if (\file_exists($file)) {
404 return \htmlentities(\file_get_contents($file));
406 return "$file not found!";
409 private static function loadView($name, $data) {
410 $content = \file_get_contents(__DIR__ .
'/views/' . $name .
'.html');
411 foreach ($data as $key => $value) {
412 $content = str_replace(
'{{' . $key .
'}}', $value, $content);
Manipulates class and namespace names Ubiquity\cache$ClassUtils This class is part of Ubiquity.
Ubiquity\utils\base$UIntrospection This class is part of Ubiquity.
Http Request utilities, wrapper for accessing to $_GET, $_POST and php://input.