vendor/symfony/error-handler/Exception/FlattenException.php line 27

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\ErrorHandler\Exception;
  11. use Symfony\Component\Debug\Exception\FatalThrowableError;
  12. use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException;
  13. use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  16. /**
  17.  * FlattenException wraps a PHP Error or Exception to be able to serialize it.
  18.  *
  19.  * Basically, this class removes all objects from the trace.
  20.  *
  21.  * @author Fabien Potencier <fabien@symfony.com>
  22.  */
  23. class FlattenException extends LegacyFlattenException
  24. {
  25.     private $message;
  26.     private $code;
  27.     private $previous;
  28.     private $trace;
  29.     private $traceAsString;
  30.     private $class;
  31.     private $statusCode;
  32.     private $statusText;
  33.     private $headers;
  34.     private $file;
  35.     private $line;
  36.     private $asString;
  37.     public static function create(\Exception $exception$statusCode null, array $headers = []): self
  38.     {
  39.         return static::createFromThrowable($exception$statusCode$headers);
  40.     }
  41.     public static function createFromThrowable(\Throwable $exceptionint $statusCode null, array $headers = []): self
  42.     {
  43.         $e = new static();
  44.         $e->setMessage($exception->getMessage());
  45.         $e->setCode($exception->getCode());
  46.         if ($exception instanceof HttpExceptionInterface) {
  47.             $statusCode $exception->getStatusCode();
  48.             $headers array_merge($headers$exception->getHeaders());
  49.         } elseif ($exception instanceof RequestExceptionInterface) {
  50.             $statusCode 400;
  51.         }
  52.         if (null === $statusCode) {
  53.             $statusCode 500;
  54.         }
  55.         if (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) {
  56.             $statusText Response::$statusTexts[$statusCode];
  57.         } else {
  58.             $statusText 'Whoops, looks like something went wrong.';
  59.         }
  60.         $e->setStatusText($statusText);
  61.         $e->setStatusCode($statusCode);
  62.         $e->setHeaders($headers);
  63.         $e->setTraceFromThrowable($exception);
  64.         $e->setClass($exception instanceof FatalThrowableError $exception->getOriginalClassName() : get_debug_type($exception));
  65.         $e->setFile($exception->getFile());
  66.         $e->setLine($exception->getLine());
  67.         $previous $exception->getPrevious();
  68.         if ($previous instanceof \Throwable) {
  69.             $e->setPrevious(static::createFromThrowable($previous));
  70.         }
  71.         return $e;
  72.     }
  73.     public function toArray(): array
  74.     {
  75.         $exceptions = [];
  76.         foreach (array_merge([$this], $this->getAllPrevious()) as $exception) {
  77.             $exceptions[] = [
  78.                 'message' => $exception->getMessage(),
  79.                 'class' => $exception->getClass(),
  80.                 'trace' => $exception->getTrace(),
  81.             ];
  82.         }
  83.         return $exceptions;
  84.     }
  85.     public function getStatusCode(): int
  86.     {
  87.         return $this->statusCode;
  88.     }
  89.     /**
  90.      * @return $this
  91.      */
  92.     public function setStatusCode($code): self
  93.     {
  94.         $this->statusCode $code;
  95.         return $this;
  96.     }
  97.     public function getHeaders(): array
  98.     {
  99.         return $this->headers;
  100.     }
  101.     /**
  102.      * @return $this
  103.      */
  104.     public function setHeaders(array $headers): self
  105.     {
  106.         $this->headers $headers;
  107.         return $this;
  108.     }
  109.     public function getClass(): string
  110.     {
  111.         return $this->class;
  112.     }
  113.     /**
  114.      * @return $this
  115.      */
  116.     public function setClass($class): self
  117.     {
  118.         $this->class false !== strpos($class"@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' $class;
  119.         return $this;
  120.     }
  121.     public function getFile(): string
  122.     {
  123.         return $this->file;
  124.     }
  125.     /**
  126.      * @return $this
  127.      */
  128.     public function setFile($file): self
  129.     {
  130.         $this->file $file;
  131.         return $this;
  132.     }
  133.     public function getLine(): int
  134.     {
  135.         return $this->line;
  136.     }
  137.     /**
  138.      * @return $this
  139.      */
  140.     public function setLine($line): self
  141.     {
  142.         $this->line $line;
  143.         return $this;
  144.     }
  145.     public function getStatusText(): string
  146.     {
  147.         return $this->statusText;
  148.     }
  149.     public function setStatusText(string $statusText): self
  150.     {
  151.         $this->statusText $statusText;
  152.         return $this;
  153.     }
  154.     public function getMessage(): string
  155.     {
  156.         return $this->message;
  157.     }
  158.     /**
  159.      * @return $this
  160.      */
  161.     public function setMessage($message): self
  162.     {
  163.         if (false !== strpos($message"@anonymous\0")) {
  164.             $message preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
  165.                 return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' $m[0];
  166.             }, $message);
  167.         }
  168.         $this->message $message;
  169.         return $this;
  170.     }
  171.     /**
  172.      * @return int|string int most of the time (might be a string with PDOException)
  173.      */
  174.     public function getCode()
  175.     {
  176.         return $this->code;
  177.     }
  178.     /**
  179.      * @return $this
  180.      */
  181.     public function setCode($code): self
  182.     {
  183.         $this->code $code;
  184.         return $this;
  185.     }
  186.     /**
  187.      * @return self|null
  188.      */
  189.     public function getPrevious()
  190.     {
  191.         return $this->previous;
  192.     }
  193.     /**
  194.      * @return $this
  195.      */
  196.     final public function setPrevious(LegacyFlattenException $previous): self
  197.     {
  198.         $this->previous $previous;
  199.         return $this;
  200.     }
  201.     /**
  202.      * @return self[]
  203.      */
  204.     public function getAllPrevious(): array
  205.     {
  206.         $exceptions = [];
  207.         $e $this;
  208.         while ($e $e->getPrevious()) {
  209.             $exceptions[] = $e;
  210.         }
  211.         return $exceptions;
  212.     }
  213.     public function getTrace(): array
  214.     {
  215.         return $this->trace;
  216.     }
  217.     /**
  218.      * @deprecated since 4.1, use {@see setTraceFromThrowable()} instead.
  219.      */
  220.     public function setTraceFromException(\Exception $exception)
  221.     {
  222.         @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.'__METHOD__), \E_USER_DEPRECATED);
  223.         $this->setTraceFromThrowable($exception);
  224.     }
  225.     /**
  226.      * @return $this
  227.      */
  228.     public function setTraceFromThrowable(\Throwable $throwable): self
  229.     {
  230.         $this->traceAsString $throwable->getTraceAsString();
  231.         return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
  232.     }
  233.     /**
  234.      * @return $this
  235.      */
  236.     public function setTrace($trace$file$line): self
  237.     {
  238.         $this->trace = [];
  239.         $this->trace[] = [
  240.             'namespace' => '',
  241.             'short_class' => '',
  242.             'class' => '',
  243.             'type' => '',
  244.             'function' => '',
  245.             'file' => $file,
  246.             'line' => $line,
  247.             'args' => [],
  248.         ];
  249.         foreach ($trace as $entry) {
  250.             $class '';
  251.             $namespace '';
  252.             if (isset($entry['class'])) {
  253.                 $parts explode('\\'$entry['class']);
  254.                 $class array_pop($parts);
  255.                 $namespace implode('\\'$parts);
  256.             }
  257.             $this->trace[] = [
  258.                 'namespace' => $namespace,
  259.                 'short_class' => $class,
  260.                 'class' => $entry['class'] ?? '',
  261.                 'type' => $entry['type'] ?? '',
  262.                 'function' => $entry['function'] ?? null,
  263.                 'file' => $entry['file'] ?? null,
  264.                 'line' => $entry['line'] ?? null,
  265.                 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [],
  266.             ];
  267.         }
  268.         return $this;
  269.     }
  270.     private function flattenArgs(array $argsint $level 0int &$count 0): array
  271.     {
  272.         $result = [];
  273.         foreach ($args as $key => $value) {
  274.             if (++$count 1e4) {
  275.                 return ['array''*SKIPPED over 10000 entries*'];
  276.             }
  277.             if ($value instanceof \__PHP_Incomplete_Class) {
  278.                 // is_object() returns false on PHP<=7.1
  279.                 $result[$key] = ['incomplete-object'$this->getClassNameFromIncomplete($value)];
  280.             } elseif (\is_object($value)) {
  281.                 $result[$key] = ['object', \get_class($value)];
  282.             } elseif (\is_array($value)) {
  283.                 if ($level 10) {
  284.                     $result[$key] = ['array''*DEEP NESTED ARRAY*'];
  285.                 } else {
  286.                     $result[$key] = ['array'$this->flattenArgs($value$level 1$count)];
  287.                 }
  288.             } elseif (null === $value) {
  289.                 $result[$key] = ['null'null];
  290.             } elseif (\is_bool($value)) {
  291.                 $result[$key] = ['boolean'$value];
  292.             } elseif (\is_int($value)) {
  293.                 $result[$key] = ['integer'$value];
  294.             } elseif (\is_float($value)) {
  295.                 $result[$key] = ['float'$value];
  296.             } elseif (\is_resource($value)) {
  297.                 $result[$key] = ['resource'get_resource_type($value)];
  298.             } else {
  299.                 $result[$key] = ['string', (string) $value];
  300.             }
  301.         }
  302.         return $result;
  303.     }
  304.     private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value): string
  305.     {
  306.         $array = new \ArrayObject($value);
  307.         return $array['__PHP_Incomplete_Class_Name'];
  308.     }
  309.     public function getTraceAsString(): string
  310.     {
  311.         return $this->traceAsString;
  312.     }
  313.     /**
  314.      * @return $this
  315.      */
  316.     public function setAsString(?string $asString): self
  317.     {
  318.         $this->asString $asString;
  319.         return $this;
  320.     }
  321.     public function getAsString(): string
  322.     {
  323.         if (null !== $this->asString) {
  324.             return $this->asString;
  325.         }
  326.         $message '';
  327.         $next false;
  328.         foreach (array_reverse(array_merge([$this], $this->getAllPrevious())) as $exception) {
  329.             if ($next) {
  330.                 $message .= 'Next ';
  331.             } else {
  332.                 $next true;
  333.             }
  334.             $message .= $exception->getClass();
  335.             if ('' != $exception->getMessage()) {
  336.                 $message .= ': '.$exception->getMessage();
  337.             }
  338.             $message .= ' in '.$exception->getFile().':'.$exception->getLine().
  339.                 "\nStack trace:\n".$exception->getTraceAsString()."\n\n";
  340.         }
  341.         return rtrim($message);
  342.     }
  343. }