使用PHP中的domdocument替换HTML字符串中某个元素中的内容

1682次阅读 69人点赞 作者: WuBin 发布时间: 2024-06-17 16:56:21
扫码到手机查看

使用正则表达式

比如我有一个html文件,我要获取第一个script标签中的JS字符串。

$indexHtml = file_get_contents('index.html');
$pattern = '/<script[^>]*>(.*?)<\/script>/is';
preg_match($pattern, $indexHtml, $match);
var_dump($match);

如果使用正则表达式进行替换的话,就会出现问题:使用preg_replace会将字符串中匹配到的每个结果都替换!

$pattern = '/<script[^>]*>(.*?)<\/script>/is';
// 替换函数
function replaceScriptContent($matches) {
    // 这里可以处理$matches[1]中的内容,它是<script>标签内的内容
    // 作为示例,我们简单地将其替换为空字符串
    return '<script type="text/javascript">/* Script content removed */</script>';
}

// 执行替换
$newHtmlContent = preg_replace_callback($pattern, 'replaceScriptContent', $indexHtml);

// 输出结果
echo $newHtmlContent;

preg_replace_callback函数用于执行替换操作。它接受一个正则表达式模式和一个回调函数,并返回替换后的字符串。回调函数replaceScriptContent用于处理每个匹配到的<script>标签的内容。

使用正则表达式来解析或修改HTML通常不是一个好主意,因为HTML结构可以非常复杂,且正则表达式在处理嵌套标签时容易出错。在大多数情况下,使用专门的HTML解析库(如DOMDocument)是更好的选择。

DOMDocument

如果你需要处理复杂的HTML文档,使用HTML解析库(如DOMDocument)是更好的选择。下面是一个使用DOMDocument的例子:

$dom = new DOMDocument();
@$dom->loadHTML($htmlContent, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$scripts = $dom->getElementsByTagName('script');
foreach ($scripts as $script) {
    // 你可以在这里处理$script节点的内容
    // 例如,移除内容或替换为其他内容
    $script->nodeValue = '/* Script content removed */';
}

$newHtmlContent = $dom->saveHTML();
echo $newHtmlContent;

在这个例子中,DOMDocument被用来加载HTML内容,然后遍历所有的<script>标签,修改它们的内容。使用DOMDocument可以更安全、更可靠地处理HTML。

如果你只想要保存特定的节点,你可以通过getElementByIdgetElementsByTagName或其他 DOM 方法获取该节点,然后将其传递给saveHTML方法:

$node = $dom->getElementById('myNodeId'); // 假设你有一个ID为myNodeId的元素
echo $dom->saveHTML($node); // 仅输出该节点的HTML内容

但是目前发现vue打包后的文档,获取后会被转义。类似于下面这种情况:

<title>&#21834;&#21834;&#21834;&#21834;</title>

尝试使用下面的方式处理,没有效果,待后续更新,仅做参考:

<?php
$htmlContent = '<html>
<head>
    <title>测试页面</title>
</head>
<body>
    <h1>欢迎来到测试页面</h1>
    <p>这是一个段落。</p>
</body>
</html>';

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true; // 格式化输出
libxml_use_internal_errors(true); // 忽略加载HTML时产生的错误
$dom->loadHTML($htmlContent, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors(); // 清除错误

echo $dom->saveHTML(); // 输出整个文档的HTML,汉字不会被转义
?>

解决DomDocument中汉字被转义

解决方式来源于知乎:https://www.zhihu.com/question/20122148

我也遇到相同的问题,解决如下:
使用下面这行代码:
`$doc->saveHTML($doc->documentElement)`
而不是
`$doc->saveHTMLFile('filepath.html');`

最终解决代码如下:

//  假设最终处理得到的信息是这些
$userInfo = [
    'user_id'    => 1234,
    'user_phone' => 13068574566
 ];
$userInfoJsVar = 'window.userInfo = ' . json_encode($userInfo, JSON_UNESCAPED_UNICODE) . ';';

// 对结构进行调整 获取第一个script标签,并添加上验证后的用户相关信息,与原本信息一起渲染在模板的html页面中
$indexHtml = file_get_contents('index.html');

// 检查字符串是否已经是UTF-8编码
$encoding = mb_detect_encoding($indexHtml, "UTF-8, ISO-8859-1, GBK");
// 如果不是UTF-8编码,则转换编码为UTF-8
if ($encoding != "UTF-8") {
    $indexHtml = mb_convert_encoding($indexHtml, "UTF-8", $encoding);
}

$dom = new DOMDocument('1.0', 'UTF-8');
if(!@$dom->loadHTML($indexHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) {
    exit('加载模板遇到错误');
}

$scripts = $dom->getElementsByTagName('script');
// 对第一个script中内容修改$scripts[0]也行
$scripts->item(0)->nodeValue = $userInfoJsVar;
// 传递的参数是解决汉字被转义问题的核心
$resultHtml = $dom->saveHTML( $dom->documentElement );
echo $resultHtml;

domDocument基本使用

从PHP5开始,PHP就为我们提供了一个强大的解析和生成XML相关操作的类,也就是我们今天要讲的 DOMDocument 类。

创建一个新的文本节点

$content = $dom->createTextNode($text);

假设我们有一个已存在的元素$element,我们将$content作为其子节点

$element = $dom->getElementById('some-id');
$element->appendChild($content);

创建一个元素

$node1 = $dom->createElement('First', 'This is First Node.');

生成div 和 p 并将p插入到div中,将div插入到文档中

$xml = new DOMDocument('1.0', 'UTF-8');
$wrapper = $xml->createElement('div', 'this is text in div');
$wrapper->setAttribute('class', 'wrapper');

$inner = $xml->createElement('p', 'text in p');
$inner->setAttribute('class', 'inner');

$wrapper->appendChild($inner);

$xml->appendChild($wrapper);
print $xml->saveHTML();
// 输出结果
// <div class="wrapper">this is text in div<p class="inner">text in p</p></div>

输出xml与html大同小异

// 生成一个XML文档
$xml = new DOMDocument('1.0', 'UTF-8');
 
$node1 = $xml->createElement('First', 'This is First Node.');
$node1->setAttribute('type', '1');
 
$node2 = $xml->createElement('Second');
$node2->setAttribute('type', '2');
$node2_child = $xml->createElement('Second-Child', 'This is Second Node Child.');
$node2->appendChild($node2_child);
 
$xml->appendChild($node1);
$xml->appendChild($node2);
print $xml->saveXML();
 
/* 输出结果
<?xml version="1.0" encoding="UTF-8"?>
<First type="1">This is First Node.</First>
<Second type="2"><Second-Child>This is Second Node Child.</Second-Child></Second>
*/

获取某个元素的name、src属性

$inputSearch = $doc->getElementById('kw');
echo $inputSearch->getAttribute('name');
// 获取所有图片的链接
$allImageLinks = [];
$imgs = $doc->getElementsByTagName('img');
foreach($imgs as $img){
    $allImageLinks[] = $img->getAttribute('src');
}
可以使用parse_url对链接进行分析,返回一个数组
parse_url('http://www.baidu.com/xxxxx');
// Array
// (
//     [host] => www.baidu.com
//     [path] => /img/baidu_jgylogo3.gif
// )

从外层中删除内层p

$wrapper->removeChild($inner); 
// <div class="wrapper">this is text in div</div>

从文档中删除外层

$xml->removeChild($wrapper); 

相关资料

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:DOMDocument
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    9395次阅读 607人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4088次阅读 303人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14311次阅读 937人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    13244次阅读 468人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    11822次阅读 945人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    16035次阅读 1277人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15032次阅读 1224人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    29489次阅读 2315人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    25456次阅读 1958人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录