javascript - DOMDocument - 从正文中获取脚本文本

标签 javascript php jquery domdocument

我想做的是从正文标记获取脚本,但仅限具有文本而不是脚本链接的脚本

例如。 <script type="text/javascript">console.log("for a test run");</script>

不是具有文件 src 的脚本。

我想将这些脚本放在 </body> 之前的页面末尾.

到目前为止我已经

        echo "<pre>";
        echo "reaches 1 <br />";
        //work for inpage scripts
        $mainBody = @$dom->getElementsByTagName('body')->item(0);
        foreach (@$dom->getElementsByTagName('body') as $head) {
            echo "reaches 2";

            foreach (@$head->childNodes as $node) {

                echo "reaches 3";
                var_dump($node);
                if ($node instanceof DOMComment) {
                    if (preg_match('/<script/i', $node->nodeValue)){
                        $src = $node->nodeValue;
                        echo "its a node";
                        var_dump($node);
                    }
                }
                if ($node->nodeName == 'script' && $node->attributes->getNamedItem('type')->nodeValue == 'text/javascript') {
                    if (@$src = $node->attributes->getNamedItem('src')->nodeValue) {
                        // yay - $src was true, so we don't do anything here
                    } else {
                        $src = $node->nodeValue;
                    }
                    echo "its a node2";
                    var_dump($node);
                }
                if (isset($src)) {
                    $move = ($this->params->get('exclude')) ? true : false;
                    foreach ($omit as $omitit) {
                        if (preg_match($omitit, $src) == 1) {
                            $move = ($this->params->get('exclude')) ? false : true;
                            break;
                        }
                    }
                    if ($move)
                        $moveme[] = $node;
                    unset($src);
                }
            }
        }
        foreach ($moveme as $moveit) {
            echo "Moving";
            print_r($moveit);
            $mainBody->appendChild($moveit->cloneNode(true));
            if ($pretty) {
                $mainBody->appendChild($newline->cloneNode(false));
            }
            $moveit->parentNode->removeChild($moveit);
        }
$mainBody = $xhtml ? $dom->saveXML() : $dom->saveHTML();

        JResponse::setBody($sanitize?preg_replace($this->sanitizews['search'],$this->sanitizews['replace'],$mainBody):$mainBody);

更新 1

问题是<script type="text/javascript">也可以位于 div 中,也可以位于嵌套 div 中。因此使用 foreach @$head->childNodes只获取最上面的html标签,不扫描可能包含<script>的内部标签标签。我不明白如何获取所有必需的脚本标签。

没有错误,但顶部节点上也没有脚本标签。

更新2

经过xpath的解答,感谢您的解答。任务有了一些进展。但现在将脚本移至页脚后,我无法删除/删除原始脚本标签。

这是我迄今为止更新的代码:

        echo "<pre>3";
//        echo "reaches 1 <br />";
        //work for inpage scripts
        $xpath = new DOMXPath($dom);
        $script_tags = $xpath->query('//body//script[not(@src)]');

        foreach ($script_tags as $tag) {
//            var_dump($tag->nodeValue);
            $moveme[] = $tag;
        }
        $mainBody = @$dom->getElementsByTagName('body')->item(0);
        foreach ($moveme as $moveItScript) {

            print_r($moveItScript->cloneNode(true));
            $mainBody->appendChild($moveItScript->cloneNode(true));
//            var_dump($moveItScript->parentNode);
//            $moveItScript->parentNode->removeChild($moveItScript);
/*            try{
                $mainBody->appendChild($moveit->cloneNode(true));
                if ($pretty) {
                    $body->appendChild($newline->cloneNode(false));
                }
                $moveit->parentNode->removeChild($moveit);
            }catch (Exception $ex){
                var_dump($ex);
            }*/
        }
        echo "</pre>";

更新3

我在 Joomla 工作,试图将脚本移动到页面的页脚。我使用了 scriptdown 插件,它将脚本从 head 标签移动到底部。但是中间页面中的脚本没有移到底部,所以导致页面内脚本无法正确响应。

我的问题现在已经解决了。发布我的解决方案代码,以便将来对某人有所帮助。

function onAfterRender() {
        $app = JFactory::getApplication();
        $doc = JFactory::getDocument();
        /* test that the page is not administrator && test that the document is HTML output */
        if ($app->isAdmin() || $doc->getType() != 'html')
            return;
        $pretty = (int)$this->params->get('pretty', 0);
        $stripcomments = (int)$this->params->get('stripcomments', 0);
        $sanitize = (int)$this->params->get('sanitize',0);
        $debug = (int)$app->getCfg('debug',0);
        if($debug) $pretty = true;
        $omit = array();
        /* now we know this is a frontend page and it is html - begin processing */
        /* first - prepare the omit array */

        if (strlen(trim($this->params->get('omit'))) > 0) {
            foreach (explode("\n", $this->params->get('omit')) as $omitme) {
                $omit[] = '/' . str_replace(array('/', '\''), array('\/', '\\\''), trim($omitme)) . '/i';
            }
            unset($omitme);
        }
        $moveme = array();
        $dom = new DOMDocument();
        $dom->recover = true;
        $dom->substituteEntities = true;
        if ($pretty) {
            $dom->formatOutput = true;
        } else {
            $dom->preserveWhiteSpace = false;
        }
        $source = JResponse::getBody();
        /* DOMDocument can get quite vocal when malformed HTML/XHTML is loaded.
         * First we grab the current level, and set the error reporting level
         * to zero, afterwards, we return it to the original value.  This trickery
         * is used to keep the logs clear of DOMDocument protests while loading the source.
         * I promise to set the level back as soon as I'm done loading source...
         */
        if(!$debug) $erlevel = error_reporting(0);
        $xhtml = (preg_match('/XHTML/', $source)) ? true : false;
        switch ($xhtml) {
            case true:
                $dom->loadXML($source);
                break;
            case false:
                $dom->loadHTML($source);
                break;
        }
        if(!$debug) error_reporting($erlevel); /* You see, error_reporting is back to normal - just like I promised */

        if ($pretty) {
            $newline = $dom->createTextNode("\n");
        }

        if($sanitize && !$debug && !$pretty) {
            $this->_sanitizeCSS($dom->getElementsByTagName('style'));
        }

        if ($stripcomments && !$debug) {
            $comments = $this->_domComments($dom);
            foreach ($comments as $node)
                if (!preg_match('/\[endif]/i', $node->nodeValue)) // we don't remove IE conditionals
                    if ($node->parentNode->nodeName != 'script') // we also don't remove comments in javascript because some developers write JS inside of a comment
                        $node->parentNode->removeChild($node);
        }
        $body = @$dom->getElementsByTagName('footer')->item(0);
        foreach (@$dom->getElementsByTagName('head') as $head) {
            foreach (@$head->childNodes as $node) {
                if ($node instanceof DOMComment) {
                    if (preg_match('/<script/i', $node->nodeValue))
                        $src = $node->nodeValue;
                }
                if ($node->nodeName == 'script' && $node->attributes->getNamedItem('type')->nodeValue == 'text/javascript') {
                    if (@$src = $node->attributes->getNamedItem('src')->nodeValue) {
                        // yay - $src was true, so we don't do anything here
                    } else {
                        $src = $node->nodeValue;
                    }
                }
                if (isset($src)) {
                    $move = ($this->params->get('exclude')) ? true : false;
                    foreach ($omit as $omitit) {
                        if (preg_match($omitit, $src) == 1) {
                            $move = ($this->params->get('exclude')) ? false : true;
                            break;
                        }
                    }
                    if ($move)
                        $moveme[] = $node;
                    unset($src);
                }
            }
        }
        foreach ($moveme as $moveit) {
            $body->appendChild($moveit->cloneNode(true));
            if ($pretty) {
                $body->appendChild($newline->cloneNode(false));
            }
            $moveit->parentNode->removeChild($moveit);
        }

        //work for inpage scripts
        $xpath = new DOMXPath($dom);
        $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);
        }

        $body = $xhtml ? $dom->saveXML() : $dom->saveHTML();
        JResponse::setBody($sanitize?preg_replace($this->sanitizews['search'],$this->sanitizews['replace'],$body):$body);
    }

最佳答案

为了只获得 <script>没有 src 的节点属性你最好使用DOMXPath :

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

变量$script_tags现在是DOMNodeList包含所有脚本标签的对象。 您现在可以循环 DOMNodeList获取所有节点并执行您想要对它们执行的任何操作:

foreach ($script_tags as $tag) {
    var_dump($tag->nodeValue);
    $moveme[] = $tag;
}

关于javascript - DOMDocument - 从正文中获取脚本文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37847743/

相关文章:

JavaScript + JQUERY : Calculating based on two input variables

javascript - jQuery点击图片显示详细图片信息的问题

php - JavaScript 中的串联变量名称

php - 删除重复条目

php - 我在我的项目中使用 PHP 的工作单元设计模式

javascript - 将文本拆分为等长的字符串,保持单词完整

JavaScript date() 对象通过 getYear(和其他)返回 NaN

php - 关于 [HTTP_X_FORWARDED_FOR] 的安全问题,我是否应该使用它而不是 [REMOTE_ADDR]?

javascript - 如何在可调整大小中添加特定的 maxWidth 选项值?

javascript - 如何通过 jquery $.window url 将 javascript 数组变量传递给 codeigniter Controller ?