From dff559dbaacfdca42d7fcb4cc68ea096b978f298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20Ma=C5=82ecki?= Date: Tue, 13 Jan 2026 13:21:28 +0100 Subject: [PATCH 1/3] feat: insights fixes --- src/Errbit/Errbit.php | 8 ++++-- src/Errbit/Errors/BaseError.php | 7 +++++ src/Errbit/Errors/Error.php | 3 ++ src/Errbit/Errors/Notice.php | 3 ++ src/Errbit/Errors/Warning.php | 3 ++ src/Errbit/Utils/Converter.php | 7 +++-- src/Errbit/Utils/XmlBuilder.php | 50 ++++++++++++++++++++++++++------- 7 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/Errbit/Errbit.php b/src/Errbit/Errbit.php index 954078c..88804b5 100644 --- a/src/Errbit/Errbit.php +++ b/src/Errbit/Errbit.php @@ -166,10 +166,14 @@ protected function shouldNotify(\Throwable $exception, array $skippedExceptions) } } $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? ''; - /** @var array $ignoreUserAgents */ + $userAgent = is_string($userAgent) ? $userAgent : ''; + /** @var list $ignoreUserAgents */ $ignoreUserAgents = $this->config['ignore_user_agent']; foreach ($ignoreUserAgents as $ua) { - if ($userAgent !== '' && str_contains($userAgent, $ua)) { + if ($userAgent === '' || !is_string($ua) || $ua === '') { + continue; + } + if (str_contains($userAgent, $ua)) { return false; } } diff --git a/src/Errbit/Errors/BaseError.php b/src/Errbit/Errors/BaseError.php index f120d5d..da91a5c 100644 --- a/src/Errbit/Errors/BaseError.php +++ b/src/Errbit/Errors/BaseError.php @@ -10,8 +10,12 @@ abstract class BaseError extends \Exception { protected string $errorFile = ''; + /** @var list> */ protected array $backtrace = []; + /** + * @param list> $backtrace + */ public function __construct( string $message = "", int $code = 0, @@ -32,6 +36,9 @@ public function getErrorFile(): string return $this->errorFile; } + /** + * @return list> + */ public function getBacktrace(): array { return $this->backtrace; diff --git a/src/Errbit/Errors/Error.php b/src/Errbit/Errors/Error.php index ccc5087..8920efe 100644 --- a/src/Errbit/Errors/Error.php +++ b/src/Errbit/Errors/Error.php @@ -4,6 +4,9 @@ class Error extends BaseError { + /** + * @param list> $backtrace + */ public function __construct( string $message, ?int $line = null, diff --git a/src/Errbit/Errors/Notice.php b/src/Errbit/Errors/Notice.php index cf31cff..9521f4c 100644 --- a/src/Errbit/Errors/Notice.php +++ b/src/Errbit/Errors/Notice.php @@ -4,6 +4,9 @@ class Notice extends BaseError { + /** + * @param list> $backtrace + */ public function __construct( string $message, ?int $line = null, diff --git a/src/Errbit/Errors/Warning.php b/src/Errbit/Errors/Warning.php index 32e5da1..dc4b22b 100644 --- a/src/Errbit/Errors/Warning.php +++ b/src/Errbit/Errors/Warning.php @@ -4,6 +4,9 @@ class Warning extends BaseError { + /** + * @param list> $backtrace + */ public function __construct( string $message, ?int $line = null, diff --git a/src/Errbit/Utils/Converter.php b/src/Errbit/Utils/Converter.php index 993ac9c..f3311b9 100644 --- a/src/Errbit/Utils/Converter.php +++ b/src/Errbit/Utils/Converter.php @@ -20,13 +20,16 @@ public static function createDefault(): Converter return new self(); } + /** + * @param list> $backtrace + */ public function convert(int $code, string $message, ?\Throwable $previous = null, string $file ='', ?int $line = null, array $backtrace = []): \Throwable { return match ($code) { E_NOTICE, E_USER_NOTICE => new Notice($message, $line, $previous, $file, $backtrace), E_WARNING, E_USER_WARNING => new Warning($message, $line, $previous, $file, $backtrace), - E_RECOVERABLE_ERROR, E_ERROR, E_CORE_ERROR => new Fatal($message, $line, $previous, $file), - default => new Error($message, $line, $previous, $file, $backtrace), + E_RECOVERABLE_ERROR, E_ERROR, E_CORE_ERROR => new Fatal($message, $line ?? 0, $previous, $file), + default => new Error($message, $line, $previous, $file, $backtrace), }; } } diff --git a/src/Errbit/Utils/XmlBuilder.php b/src/Errbit/Utils/XmlBuilder.php index c418ffc..a09ae58 100644 --- a/src/Errbit/Utils/XmlBuilder.php +++ b/src/Errbit/Utils/XmlBuilder.php @@ -2,6 +2,7 @@ declare(strict_types=1); namespace Errbit\Utils; +use DOMElement; use SimpleXMLElement; /** @@ -41,8 +42,8 @@ public function __construct(?\SimpleXMLElement $xml = null) /** * Insert a tag into the XML. * - * @param string $name the name of the tag, required. - * @param mixed $value the text value of the element, optional + * @param string $name the name of the tag, required + * @param mixed $value the text value of the element, optional * @param array $attributes an array of attributes for the tag, optional * @param callable|null $callback a callback to receive an XmlBuilder for the new tag, optional * @param bool $getLastChild whether to get the last child element @@ -55,10 +56,23 @@ public function tag(string $name, mixed $value = '', array $attributes = [], ?ca $this->_xml->{$name}[$idx] = $this->normalizeValue($value); - foreach ($attributes as $attr => $v) { - $this->_xml->{$name}[$idx][$attr] = $this->normalizeValue($v); + $childElement = null; + if (isset($this->_xml->{$name}[$idx]) && $this->_xml->{$name}[$idx] instanceof SimpleXMLElement) { + $childElement = $this->_xml->{$name}[$idx]; + } elseif ($this->_xml->{$name} instanceof SimpleXMLElement) { + $childElement = $this->_xml->{$name}; } - $node = new self($this->_xml->$name); + + if ($childElement instanceof SimpleXMLElement) { + foreach ($attributes as $attr => $v) { + if (!is_string($attr) || $attr === '') { + continue; + } + $this->setAttribute($childElement, $attr, $this->normalizeValue($v)); + } + } + + $node = new self($childElement instanceof SimpleXMLElement ? $childElement : null); if ($getLastChild) { $array = $this->_xml->xpath($name."[last()]"); if (is_array($array)) { @@ -79,14 +93,18 @@ public function tag(string $name, mixed $value = '', array $attributes = [], ?ca /** * Add an attribute to the current element. * - * @param String $name the name of the attribute - * @param String $value the value of the attribute + * @param string $name the name of the attribute + * @param mixed $value the value of the attribute * * @return static the current builder */ - public function attribute($name, $value): static + public function attribute(string $name, mixed $value): static { - $this->_xml[$name] = $this->normalizeValue($value); + if ($name === '') { + return $this; + } + + $this->setAttribute($this->_xml, $name, $this->normalizeValue($value)); return $this; } @@ -143,6 +161,18 @@ public function asXml(): string */ public static function utf8ForXML($string) { - return preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string); + $filtered = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string); + + return is_string($filtered) ? $filtered : ''; + } + + private function setAttribute(SimpleXMLElement $element, string $name, string $value): void + { + $domNode = dom_import_simplexml($element); + if (!$domNode instanceof DOMElement) { + return; + } + + $domNode->setAttribute($name, $value); } } From bd9ae11b3b8b77e369de61027473f9277eab74a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20Ma=C5=82ecki?= Date: Tue, 13 Jan 2026 14:33:44 +0100 Subject: [PATCH 2/3] fixing unit tests --- src/Errbit/Utils/XmlBuilder.php | 86 +++++---------------------------- 1 file changed, 13 insertions(+), 73 deletions(-) diff --git a/src/Errbit/Utils/XmlBuilder.php b/src/Errbit/Utils/XmlBuilder.php index a09ae58..ed39429 100644 --- a/src/Errbit/Utils/XmlBuilder.php +++ b/src/Errbit/Utils/XmlBuilder.php @@ -2,7 +2,6 @@ declare(strict_types=1); namespace Errbit\Utils; -use DOMElement; use SimpleXMLElement; /** @@ -32,7 +31,7 @@ class XmlBuilder /** * Instantiate a new XmlBuilder. * - * @param SimpleXMLElement $xml the parent node (only used internally) + * @param SimpleXMLElement|null $xml the parent node (only used internally) */ public function __construct(?\SimpleXMLElement $xml = null) { @@ -42,37 +41,24 @@ public function __construct(?\SimpleXMLElement $xml = null) /** * Insert a tag into the XML. * - * @param string $name the name of the tag, required - * @param mixed $value the text value of the element, optional + * @param string $name the name of the tag, required. + * @param string $value the text value of the element, optional * @param array $attributes an array of attributes for the tag, optional * @param callable|null $callback a callback to receive an XmlBuilder for the new tag, optional * @param bool $getLastChild whether to get the last child element * * @return XmlBuilder a builder for the inserted tag */ - public function tag(string $name, mixed $value = '', array $attributes = [], ?callable $callback = null, bool $getLastChild = false): XmlBuilder + public function tag(string $name, string $value = '', array $attributes = [], ?callable $callback = null, bool $getLastChild = false): XmlBuilder { $idx = is_countable($this->_xml->$name) ? count($this->_xml->$name) : 0; - $this->_xml->{$name}[$idx] = $this->normalizeValue($value); + $this->_xml->{$name}[$idx] = $value; - $childElement = null; - if (isset($this->_xml->{$name}[$idx]) && $this->_xml->{$name}[$idx] instanceof SimpleXMLElement) { - $childElement = $this->_xml->{$name}[$idx]; - } elseif ($this->_xml->{$name} instanceof SimpleXMLElement) { - $childElement = $this->_xml->{$name}; + foreach ($attributes as $attr => $v) { + $this->_xml->{$name}[$idx][(string) $attr] = (string) $v; } - - if ($childElement instanceof SimpleXMLElement) { - foreach ($attributes as $attr => $v) { - if (!is_string($attr) || $attr === '') { - continue; - } - $this->setAttribute($childElement, $attr, $this->normalizeValue($v)); - } - } - - $node = new self($childElement instanceof SimpleXMLElement ? $childElement : null); + $node = new self($this->_xml->$name); if ($getLastChild) { $array = $this->_xml->xpath($name."[last()]"); if (is_array($array)) { @@ -93,54 +79,18 @@ public function tag(string $name, mixed $value = '', array $attributes = [], ?ca /** * Add an attribute to the current element. * - * @param string $name the name of the attribute - * @param mixed $value the value of the attribute + * @param string $name the name of the attribute + * @param string $value the value of the attribute * * @return static the current builder */ - public function attribute(string $name, mixed $value): static + public function attribute(string $name, string $value): static { - if ($name === '') { - return $this; - } - - $this->setAttribute($this->_xml, $name, $this->normalizeValue($value)); + $this->_xml[$name] = $value; return $this; } - /** - * Cast any scalar or object value into a string for XML nodes. - */ - private function normalizeValue(mixed $value): string - { - if ($value instanceof \Stringable) { - return (string) $value; - } - - if (is_object($value)) { - return sprintf('[%s]', $value::class); - } - - if (is_bool($value)) { - return $value ? 'true' : 'false'; - } - - if (null === $value) { - return ''; - } - - if (is_resource($value)) { - return sprintf('[resource:%s]', get_resource_type($value)); - } - - if (is_array($value)) { - return '[array]'; - } - - return (string) $value; - } - /** * Return this XmlBuilder as a string of XML. * @@ -159,20 +109,10 @@ public function asXml(): string * * @return string escaped string */ - public static function utf8ForXML($string) + public static function utf8ForXML(string $string): string { $filtered = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string); return is_string($filtered) ? $filtered : ''; } - - private function setAttribute(SimpleXMLElement $element, string $name, string $value): void - { - $domNode = dom_import_simplexml($element); - if (!$domNode instanceof DOMElement) { - return; - } - - $domNode->setAttribute($name, $value); - } } From d7ce87e7091a1deb4ead18b76d25d425e532e942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20Ma=C5=82ecki?= Date: Tue, 13 Jan 2026 14:59:00 +0100 Subject: [PATCH 3/3] fix: unit test fix --- src/Errbit/Utils/XmlBuilder.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Errbit/Utils/XmlBuilder.php b/src/Errbit/Utils/XmlBuilder.php index ed39429..a520fcf 100644 --- a/src/Errbit/Utils/XmlBuilder.php +++ b/src/Errbit/Utils/XmlBuilder.php @@ -42,17 +42,23 @@ public function __construct(?\SimpleXMLElement $xml = null) * Insert a tag into the XML. * * @param string $name the name of the tag, required. - * @param string $value the text value of the element, optional + * @param mixed $value the text value of the element, optional * @param array $attributes an array of attributes for the tag, optional * @param callable|null $callback a callback to receive an XmlBuilder for the new tag, optional * @param bool $getLastChild whether to get the last child element * * @return XmlBuilder a builder for the inserted tag */ - public function tag(string $name, string $value = '', array $attributes = [], ?callable $callback = null, bool $getLastChild = false): XmlBuilder + public function tag(string $name, mixed $value = '', array $attributes = [], ?callable $callback = null, bool $getLastChild = false): XmlBuilder { $idx = is_countable($this->_xml->$name) ? count($this->_xml->$name) : 0; + if (is_object($value)) { + $value = "[" . $value::class . "]"; + } else { + $value = (string) $value; + } + $this->_xml->{$name}[$idx] = $value; foreach ($attributes as $attr => $v) {