Inline Java Script im HTML verschieben.

Manchmal steht man einfach nur vor gerenderten Tatsachen, wie z.B. einer ordnungsgemäß eingebundene jQuery Bibliothek am Ende eines HTML Dokumentes und einem, irgendwo ins HTML eingebettete Java Script, welche von jQuery abhängig ist.

Mit dem PHP DOMDocument und XPath kann man die <script></script> Blöcke ans Ende des HTML Dokuments verschieben, ganz ohne Reguläre Ausdrücke.

Das einzige was zur Falle werden kann, ist unsauberes HTML. Sind im Dokument ids nicht eindeutig oder Sonderzeichen wie & nicht mit htmlspecialchars('&') codiert, dann gibt der DOM Parser Warnungen aus. Die kann man aber zur Not unterdrücken. Besser ist es jedoch auf valides HTML in der Ausgabe zu achten.


<p id="paragraph">Invalider Text & Co</p>
<div id="paragraph">Text &amp; Co</div>

Hier ist der Beispielcode und ein lauffähiger Test:


<?php
$html = <<<HTML
<html>
    <head>
    </head>
    <body>
        <script>
            $('h1').addClass('header');
        </script>
        <h1>DOMDocument</h1>
        <p>Text<p>
        <script src="jquery.js"></script>

        <!-- inline script should appear below -->
    </body>
</html>
HTML;


echo move_script($html);

function move_script($html)
{
    $dom = new DOMDocument();
    $dom->recover = true;
    //$dom->substituteEntities = true;
    $dom->formatOutput = true;
    $dom->preserveWhiteSpace = false;

    // set error level
    //$internalErrors = libxml_use_internal_errors(true);
    $dom->loadHTML($html);
    // Restore error level
    //libxml_use_internal_errors($internalErrors);

    $xpath = new DOMXPath($dom);
    // grab the inline scripts.
    $script_tags = $xpath->query('//body//script[not(@src)]');

    $mainBody = @$dom->getElementsByTagName('body')->item(0);
    foreach ($script_tags as $tag) {
        $mainBody->appendChild($tag->cloneNode(true));
        $tag->parentNode->removeChild($tag);
    }

    return $dom->saveHTML();
}