Thay đổi thuộc tính mặc định của bài viết src, alt, srcset, sizes, lazysizes (ok)

Trước

Sau

function add_lazyload($content) {
  $content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
  $dom = new DOMDocument();
  @$dom->loadHTML($content);
  $images = [];
  foreach ($dom->getElementsByTagName('img') as $node) {
    $images[] = $node;
  }
  foreach ($images as $node) {
  	echo '<pre>';
  		var_export($node);
  	echo '</pre>';
   	$fallback = $node->cloneNode(true);
   	$oldsrc = $node->getAttribute('src');
   	$node->setAttribute('data-src', $oldsrc );
   	$newsrc = 'https://d1zczzapudl1mr.cloudfront.net/blank-kraken.gif';
   	$node->setAttribute('src', $newsrc);
   	$oldsrcset = $node->getAttribute('srcset');
   	$node->setAttribute('data-srcset', $oldsrcset );
   	$newsrcset = '';
   	$node->setAttribute('srcset', $newsrcset);
   	$classes = $node->getAttribute('class');
   	$newclasses = $classes . ' lazyload';
   	$node->setAttribute('class', $newclasses);
   	$noscript = $dom->createElement('noscript', '');
   	$node->parentNode->insertBefore($noscript, $node);
   	$noscript->appendChild($fallback);
  }
  $newHtml = preg_replace('/^<!DOCTYPE.+?>/', '', str_replace( array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''),
  $dom->saveHTML()));
  return $newHtml;
}
add_filter('the_content', 'add_lazyload', 10);

Một ví dụ đã hoàn thành :)

<?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->setAttribute('src', $src);
  // $noscript->appendChild($node);
  $image->setAttribute('data-src', $src);
  // $image->removeAttribute('src');
  // $image->parentNode->appendChild($noscript);
}
$body = $doc->saveHTML();
echo '<pre>';
  var_export($body);
echo '</pre>';
<?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;

Ask QuestionAsked 3 years, 11 months agoActive 3 years, 10 months agoViewed 1k times1

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;
  • Afaik div's don't have src attribute. – Pedro Lobito May 23 '17 at 23:05

  • 1getElementsByTagName returns a live NodeList, at least according to DOM specification. If that is true for PHP/DomDocuments implementation as well, then I am not sure whether it's a good idea to loop over such a NodeList while moving around elements inside it ... – CBroe May 23 '17 at 23:09

  • 1Well the thing is that it works with a div but not with an img – Cesar May 23 '17 at 23:51

  • @CBroe You were right the problem was in fact that getElementsByTagName return a live node list – Cesar Jun 12 '17 at 15:13

Add a comment

1 Answer

ActiveOldestVotes1

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();

Share

Last updated