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);
+ }
}