diff --git a/src/PHPHtmlParser/Content.php b/src/PHPHtmlParser/Content.php index 24bca18..66bc779 100755 --- a/src/PHPHtmlParser/Content.php +++ b/src/PHPHtmlParser/Content.php @@ -4,6 +4,7 @@ namespace PHPHtmlParser; +use PHPHtmlParser\Exceptions\ContentLengthException; use PHPHtmlParser\Exceptions\LogicalException; /** @@ -74,14 +75,27 @@ public function char(?int $char = null): string * Moves the current position forward. * * @chainable + * @throws ContentLengthException */ public function fastForward(int $count): Content { + if (!$this->canFastForward()) { + // trying to go over the content length, throw exception + throw new ContentLengthException('Attempt to fastForward pass the length of the content.'); + } $this->pos += $count; return $this; } + /** + * Checks if we can move the position forward. + */ + public function canFastForward(): bool + { + return \strlen($this->content) > $this->pos; + } + /** * Moves the current position backward. * @@ -197,14 +211,15 @@ public function copyByToken(string $token, bool $char = false, bool $escape = fa /** * Skip a given set of characters. * - * @return Content|string + * @throws LogicalException */ - public function skip(string $string, bool $copy = false) + public function skip(string $string, bool $copy = false): string { $len = \strspn($this->content, $string, $this->pos); - - // make it chainable if they don't want a copy - $return = $this; + if ($len === false) { + throw new LogicalException('Strspn returned false with position ' . $this->pos . '.'); + } + $return = ''; if ($copy) { $return = \substr($this->content, $this->pos, $len); if ($return === false) { diff --git a/src/PHPHtmlParser/Dom.php b/src/PHPHtmlParser/Dom.php index 1cba505..d23110d 100755 --- a/src/PHPHtmlParser/Dom.php +++ b/src/PHPHtmlParser/Dom.php @@ -12,6 +12,7 @@ use PHPHtmlParser\Dom\TextNode; use PHPHtmlParser\Exceptions\ChildNotFoundException; use PHPHtmlParser\Exceptions\CircularException; +use PHPHtmlParser\Exceptions\ContentLengthException; use PHPHtmlParser\Exceptions\CurlException; use PHPHtmlParser\Exceptions\LogicalException; use PHPHtmlParser\Exceptions\NotLoadedException; @@ -646,7 +647,13 @@ private function parseTag(): array } // check if this is a closing tag - if ($this->content->fastForward(1)->char() == '/') { + try { + $this->content->fastForward(1); + } catch (ContentLengthException $exception) { + // we are at the end of the file + return $return; + } + if ($this->content->char() == '/') { // end tag $tag = $this->content->fastForward(1) ->copyByToken('slash', true); @@ -683,7 +690,12 @@ private function parseTag(): array ) { $space = $this->content->skipByToken('blank', true); if (empty($space)) { - $this->content->fastForward(1); + try { + $this->content->fastForward(1); + } catch (ContentLengthException $exception) { + // reached the end of the content + break; + } continue; } @@ -764,7 +776,9 @@ private function parseTag(): array } } - $this->content->fastForward(1); + if ($this->content->canFastForward()) { + $this->content->fastForward(1); + } $return['status'] = true; $return['node'] = $node; diff --git a/src/PHPHtmlParser/Exceptions/ContentLengthException.php b/src/PHPHtmlParser/Exceptions/ContentLengthException.php new file mode 100644 index 0000000..83c9e77 --- /dev/null +++ b/src/PHPHtmlParser/Exceptions/ContentLengthException.php @@ -0,0 +1,14 @@ +assertEquals(' [wprs_alert type="success" content="this is a short code" /] ', $node->innerHtml); } + + public function testBrokenHtml() + { + $dom = new Dom(); + $dom->loadStr('assertEquals('', $dom->outerHtml); + } }