Cesar
Cesar

Reputation: 4116

Can't append img element using php domdocument

I'm having a weird issue trying to append an image element to a noscript element using php DomDocument.

If I create a new div node I can append it without issue to the noscript element but as soon as a try to append an image element the script just times out.

What am I doing wrong?

<?php

$html = '<!DOCTYPE html><html><head><title>Sample</title></head><body><img src="https://example.com/images/example.jpg"></body></html>';

$doc = new DOMDocument();
$doc->loadHTML($html);

$images = $doc->getElementsByTagName('img');

foreach ($images as $image) {
    $src = $image->getAttribute('src');
    $noscript = $doc->createElement('noscript');

    $node = $doc->createElement('div');
    //$node = $doc->createElement('img'); If a uncomment this line the script just times out

    $node->setAttribute('src', $src);

    $noscript->appendChild($node);

    $image->setAttribute('x-data-src', $src);
    $image->removeAttribute('src');
    $image->parentNode->appendChild($noscript);
    //$image->parentNode->appendChild($newImage);
}
$body = $doc->saveHTML();

echo $body;

Upvotes: 2

Views: 2022

Answers (1)

Tim Morton
Tim Morton

Reputation: 2644

You're getting caught in a recursive loop. This will help you visualize what's going on. I've added indenting for clarity:

php > $html = '<!DOCTYPE html><html><head><title>Sample</title></head><body><img src="https://example.com/images/example.jpg"></body></html>';
php > 
php > $doc = new DOMDocument();
php > $doc->loadHTML($html);
php > 
php > $images = $doc->getElementsByTagName('img');
php > 
php > $count=0;
php > foreach ($images as $image) {
php {     $count++;
php {     if($count>4) {
php {         die('limit exceeded'); 
php {     }
php { 
php {     $src = $image->getAttribute('src');
php {     $noscript = $doc->createElement('noscript');
php { 
php {     //$node = $doc->createElement('div');
php {     $node = $doc->createElement('img'); //If a uncomment this line the script just times out
php { 
php {     $node->setAttribute('src', $src);
php { 
php {     $noscript->appendChild($node);
php { 
php {     $image->setAttribute('x-data-src', $src);
php {     $image->removeAttribute('src');
php {     $image->parentNode->appendChild($noscript);
php {     //$image->parentNode->appendChild($newImage);
php { 
php { }
limit exceeded
php > $body = $doc->saveHTML();
php > 
php > echo $body;
<!DOCTYPE html>
<html><head><title>Sample</title></head><body>
<img x-data-src="https://example.com/images/example.jpg">
<noscript>
    <img x-data-src="https://example.com/images/example.jpg">
        <noscript>
        <img x-data-src="https://example.com/images/example.jpg">
            <noscript>
            <img x-data-src="https://example.com/images/example.jpg">
                <noscript>
                <img src="https://example.com/images/example.jpg">
                </noscript>
            </noscript>
        </noscript>
    </noscript>
    </body></html>
php > 

The troublesome line causing the recursion is

$image->parentNode->appendChild($noscript);

if you comment that out, the recursion goes away. Notice that when it recurses, the x-data-src is being applied to all but the last one.

I haven't quite figured out what is causing this behaviour, but hopefully being able to visualize it will help you diagnose it further.

**UPDATE

The OP took this and ran with it, and completed the answer with his solution as shown below.


The problem was in fact that getElementsByTagName returns a LiveNodeList so appending an image to the doc will cause the infinite recursion.

I solved it by first collecting all the image tags in a simple array

<?php

$html = '<!DOCTYPE html><html><head><title>Sample</title></head><body><img src="https://example.com/images/example.jpg"></body></html>';

$doc = new DOMDocument();
$doc->loadHTML($html);

$images = $doc->getElementsByTagName('img');

$normal_array = [];
foreach ($images as $image) {
    $normal_array[] = $image;
}


// Now we have all tags in a simple array NOT in a Live Node List

foreach ($normal_array as $image) {

    $src = $image->getAttribute('src');
    $noscript = $doc->createElement('noscript');

    $node = $doc->createElement('img'); //If a uncomment this line the script just times out
    $node->setAttribute('src', $src);

    $noscript->appendChild($node);

    $image->setAttribute('x-data-src', $src);
    $image->removeAttribute('src');
    $image->parentNode->appendChild($noscript);

    //$image->parentNode->appendChild($newImage);

}

$body = $doc->saveHTML();

Upvotes: 1

Related Questions