[英]PHP 5.4.16 DOMDocument removes parts of Javascript
我嘗試將HTML頁面從遠程服務器加載到PHP腳本中,該腳本應使用DOMDocument類處理HTML。 但是我已經看到,DOMDocument類刪除了HTML頁面隨附的Javascript的某些部分。 有一些事情像:
<script type="text/javascript">
//...
function printJSPage() {
var printwin=window.open('','haha','top=100,left=100,width=800,height=600');
printwin.document.writeln(' <table border="0" cellspacing="5" cellpadding="0" width="100%">');
printwin.document.writeln(' <tr>');
printwin.document.writeln(' <td align="left" valign="bottom">');
//...
printwin.document.writeln('</td>');
//...
}
</script>
但是DOMDocument改變了,即行
printwin.document.writeln('</td>');
至
printwin.document.writeln(' ');
以及其他很多事情(例如,最后一個腳本標記不再存在。結果,我得到了一個完整的銷毀頁面,無法進一步發送。
因此,我認為DOMDocument在Javascript代碼中的HTML標記方面存在問題,並嘗試更正該代碼以生成格式正確的文檔。 我可以阻止DOMDocument中的Javascript解析嗎?
PHP代碼片段為:
$stdin = file_get_contents('php://stdin');
$dom = new \DOMDocument();
@$dom->loadHTML($stdin);
return $dom->saveHTML(); // will produce wrong HTML
//return $stdin; // will produce correct HTML
我已經存儲了兩個HTML版本,並與Meld進行了比較。
我也測試過
@$dom->loadXML($stdin);
return $dom->saveHTML();
但是我沒有從物體上得到任何東西。
這可能會有所幫助。 這個想法是用保證有效的HTML和唯一的字符串替換腳本內容,然后將其替換。
它將腳本標記內的所有內容替換為這些內容的MD5,然后將其替換回來。
$scriptContainer = [];
$str = preg_replace_callback ("#<script([^>]*)>(.*?)</script>#s", function ($matches) use (&$scriptContainer) {
$scriptContainer[md5($matches[2])] = $matches[2];
return "<script".$matches[1].">".md5($matches[2])."</script>";
}, $str);
$dom = new \DOMDocument();
@$dom->loadHTML($str);
$final = strtr($dom->saveHTML(), $scriptContainer);
由於使用str_replace(array_keys($scriptContainer), $scriptContainer, $dom->saveHTML())
格式化數組的方式, strtr
在這里非常方便。
我非常驚訝PHP無法正確解析HTML內容。 它似乎是在解析XML內容(這也是錯誤的,因為CDATA內容是解析的,而不是按字面值處理)。 但是就是這樣,如果您想要一個真正的文檔解析器,那么您應該考慮使用jsdom的Node.js解決方案
如果<script>
中有<script>
,則以下(不是很聰明)的解決方案將處理該問題。 仍然存在一個問題:如果<script>
標記不平衡,則解決方案將不起作用。 如果您的Javascript使用String.fromCharCode
來打印String </script>
,則會發生這種情況。
$scriptContainer = array();
function getPosition($tag) {
return $tag[0][1];
}
function getContent($tag) {
return $tag[0][0];
}
function isStart($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "<s");
}
function isEnd($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "</");
}
function mask($str, $scripts) {
global $scriptContainer;
$res = "";
$start = null;
$stop = null;
$idx = 0;
$count = 0;
foreach ($scripts as $tag) {
if (isStart($tag)) {
$count++;
$start = ($start === null) ? $tag : $start;
}
if (isEnd($tag)) {
$count--;
$stop = ($count == 0) ? $tag : $stop;
}
if ($start !== null && $stop !== null) {
$res .= substr($str, $idx, getPosition($start) - $idx);
$res .= getContent($start);
$code = substr($str, getPosition($start) + strlen(getContent($start)), getPosition($stop) - getPosition($start) - strlen(getContent($start)));
$hash = md5($code);
$res .= $hash;
$res .= getContent($stop);
$scriptContainer[$hash] = $code;
$idx = getPosition($stop) + strlen(getContent($stop));
$start = null;
$stop = null;
}
}
$res .= substr($str, $idx);
return $res;
}
preg_match_all("#\<script[^\>]*\>|\<\/script\>#s", $html, $scripts, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);
$html = mask($html, $scripts);
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_use_internal_errors(false);
// handle some things within DOM
echo strtr($dom->saveHTML(), $scriptContainer);
如果將preg_match_all
的“ script”字符串替換為“ style”,則還可以屏蔽CSS樣式,該樣式也可以包含標簽名稱(即,在注釋中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.