将所有相对 URL 替换为绝对 URL

2024-02-01

我看过一些答案(比如this one https://stackoverflow.com/questions/31347340/convert-all-relative-urls-to-absolute-urls-while-maintaining-contents),但我有一些更复杂的场景,我不确定如何解释。

我基本上有完整的 HTML 文档。我需要更换每一个相对 URL 与绝对 URL。

潜在 HTML 中的元素如下所示,也可能是其他情况:

<img src="/relative/url/img.jpg" />
<form action="/">
<form action="/contact-us/">
<a href='/relative/url/'>Note the Single Quote</a>
<img src="//example.com/protocol-relative-img.jpg" />

期望的输出是:

// "//example.com/" is ideal, but "http(s)://example.com/" are acceptable

<img src="//example.com/relative/url/img.jpg" />
<form action="//example.com/">
<form action="//example.com/contact-us/">
<a href='//example.com/relative/url/'>Note the Single Quote</a>
<img src="//example.com/protocol-relative-img.jpg" /> <!-- Unmodified -->

我不想替换协议相对 URL,因为它们已经用作绝对 URL。我已经想出了一些有效的代码,但我想知道我是否可以清理一下它,因为它是极其重复的。

但我必须考虑单引号和双引号属性值src, href, and action(我是否缺少任何可以具有相对 URL 的属性?),同时避免使用协议相对 URL。

这是我到目前为止所拥有的:

// Make URL replacement protocol relative to not break insecure/secure links
$url = str_replace( array( 'http://', 'https://' ), '//', $url );

// Temporarily Modify Protocol-Relative URLS
$str = str_replace( 'src="//', 'src="::TEMP_REPLACE::', $str );
$str = str_replace( "src='//", "src='::TEMP_REPLACE::", $str );
$str = str_replace( 'href="//', 'href="::TEMP_REPLACE::', $str );
$str = str_replace( "href='//", "href='::TEMP_REPLACE::", $str );
$str = str_replace( 'action="//', 'action="::TEMP_REPLACE::', $str );
$str = str_replace( "action='//", "action='::TEMP_REPLACE::", $str );

// Replace all other Relative URLS
$str = str_replace( 'src="/', 'src="'. $url .'/', $str );
$str = str_replace( "src='/", "src='". $url ."/", $str );
$str = str_replace( 'href="/', 'href="'. $url .'/', $str );
$str = str_replace( "href='/", "href='". $url ."/", $str );
$str = str_replace( 'action="/', 'action="'. $url .'/', $str );
$str = str_replace( "action='/", "action='". $url ."/", $str );

// Change Protocol Relative URLs back
$str = str_replace( 'src="::TEMP_REPLACE::', 'src="//', $str );
$str = str_replace( "src='::TEMP_REPLACE::", "src='//", $str );
$str = str_replace( 'href="::TEMP_REPLACE::', 'href="//', $str );
$str = str_replace( "href='::TEMP_REPLACE::", "href='//", $str );
$str = str_replace( 'action="::TEMP_REPLACE::', 'action="//', $str );
$str = str_replace( "action='::TEMP_REPLACE::", "action='//", $str );

我的意思是,它有效,但它是uuugly,我想可能有更好的方法来做到这一点。


新答案

如果您的真实 html 文档是有效的(并且具有父/包含标签),那么最合适和可靠的技术将是使用适当的 DOM 解析器。

以下是如何使用 DOMDocument 和 Xpath 优雅地定位和替换指定的标签属性:

代码 1 - 嵌套 Xpath 查询:(Demo https://3v4l.org/1taUc)

$domain = '//example.com';
$tagsAndAttributes = [
    'img' => 'src',
    'form' => 'action',
    'a' => 'href'
];

$dom = new DOMDocument; 
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($tagsAndAttributes as $tag => $attr) {
    foreach ($xpath->query("//{$tag}[not(starts-with(@{$attr}, '//'))]") as $node) {
        $node->setAttribute($attr, $domain . $node->getAttribute($attr));
    }
}
echo $dom->saveHTML();

Code2 - 带条件块的单个 Xpath 查询:(Demo https://3v4l.org/Ut8Dr)

$domain = '//example.com';
$targets = [
    "//img[not(starts-with(@src, '//'))]",
    "//form[not(starts-with(@action, '//'))]",
    "//a[not(starts-with(@href, '//'))]"
];

$dom = new DOMDocument; 
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query(implode('|', $targets)) as $node) {
    if ($src = $node->getAttribute('src')) {
        $node->setAttribute('src', $domain . $src);
    } elseif ($action = $node->getAttribute('action')) {
        $node->setAttribute('action', $domain . $action);
    } else {
        $node->setAttribute('href', $domain . $node->getAttribute('href'));
    }
}
echo $dom->saveHTML();

旧答案:(...正则表达式不是“DOM 感知”的,并且容易受到意外破坏)

如果我正确理解你,你心里有一个基本值,你只想将它应用到相对路径。

图案演示 https://regex101.com/r/AwnWuS/1

Code: (Demo https://3v4l.org/6vtMu)

$html=<<<HTML
<img src="/relative/url/img.jpg" />
<form action="/">
<a href='/relative/url/'>Note the Single Quote</a>
<img src="//site.com/protocol-relative-img.jpg" />
HTML;

$base='https://example.com';

echo preg_replace('~(?:src|action|href)=[\'"]\K/(?!/)[^\'"]*~',"$base$0",$html);

Output:

<img src="https://example.com/relative/url/img.jpg" />
<form action="https://example.com/">
<a href='https://example.com/relative/url/'>Note the Single Quote</a>
<img src="//site.com/protocol-relative-img.jpg" />

模式细分:

~                      #Pattern delimiter
(?:src|action|href)    #Match: src or action or href
=                      #Match equal sign
[\'"]                  #Match single or double quote
\K                     #Restart fullstring match (discard previously matched characters
/                      #Match slash
(?!/)                  #Negative lookahead (zero-length assertion): must not be a slash immediately after first matched slash
[^\'"]*                #Match zero or more non-single/double quote characters
~                      #Pattern delimiter
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将所有相对 URL 替换为绝对 URL 的相关文章

随机推荐

  • 删除重复的尾部斜杠

    我想检测php如果一个字符串像 string包括重复的尾部斜杠 例如 string http somepage com something some html to string http somepage com something so
  • 在 iOS 上使用 Cordova 1.6 设置外部起始页

    是否可以加载外部index html 包含cordova js 而不是本地index html 我在 appdelegate m 中找到了这段代码 self viewController wwwFolderName www self vie
  • 如何在 NodeJs 中安排 Google 会议并获取会议链接?

    在我的项目中 我必须在给定时间在两个用户之间安排一次谷歌会议 我在 NodeJS 中拥有其电子邮件 ID 有人能帮我解决这个问题吗 您将需要使用谷歌日历API https developers google com calendar api
  • 使用 BlueSnap 托管支付字段轻松开始;

    您好 我正在寻找一个可以复制并粘贴到我的网站中的简单脚本 以便我可以开始使用 BlueSnap 的 HPF 字段进行销售 该表单应包括取回代币并向购物者收费所需的最基本元素 我不是在寻找任何设计 只是在寻找功能 我有基础知识 但我需要看看如
  • xml解析-代码重构问题

    我有以下 xml
  • 使用 rxjs 处理刷新令牌

    自从我开始使用 angular2 以来 我已经设置了我的服务来返回 T 的 Observable 在服务中 我将进行 map 调用 并且使用这些服务的组件将仅使用 subscribe 来等待响应 对于这些简单的场景 我真的不需要深入研究 r
  • 从 JavaScript 加载图像

    在我的 Grails 应用程序中 我有一个目录web app images carousel slides包含以下文件 foo png foo thumbnail png bar png bar thumbnail png 我的应用程序正在
  • 如何以惯用的方式计算有多少元素满足条件?

    有了这些数据 gt data 1 1290603356 1290603360 1290603350 1290603344 1290603340 1290603373 7 1290603354 1290603359 1290603345 12
  • QGLWidget 在 Mac OS X Lion 下无法正常工作

    正如你所看到的 我不知道为什么它根本不起作用 When the program run it will look like this 我正在使用 macports 的 qt4 mac v4 8 2 看来该包是预编译的 这是来源 主要 cpp
  • 控制器中的 GGTS 重复方法名称/签名错误

    我正在使用基于 eclipse 4 3 1 64 位版本的最新 GGTS v3 4 在 Grails 2 3 2 上开发应用程序 我的类路径中的每个控制器都有一个错误 每个控制器类都有两个相同的错误 Groovy 类 package Som
  • django 模板中的逗号分隔列表

    If fruits是列表 apples oranges pears 有没有一种使用 django 模板标签快速生成 苹果 橙子和梨 的方法 I know it s not difficult to do this using a loop
  • 如何处理函数数组中的重复函数调用?

    我正在尝试按顺序执行以下函数 同步 异步 数组 避免callbackHell 实现函数runCallbacksInSequence 我需要实现自己的函数来了解回调的工作原理并避免使用 Async js 这是我到目前为止所拥有的 功能runC
  • 在 pandas 数据框替换功能中使用正则表达式匹配组

    我刚刚学习 python pandas 喜欢它的强大和简洁 在数据清理期间 我想使用正则表达式对数据框中的列进行替换 但我想重新插入匹配的部分 组 简单示例 姓氏 名字 gt 名字 姓氏 我尝试了类似以下的内容 实际情况更复杂 所以请原谅简
  • Hyperledger Fabric 了解 MSP

    我想清楚MSP的用途 所以我的问题是 当用户出于任何原因想要使用某个通道时 本地 MSP 会为其提供一个带有私钥的身份 在文档中说 MSP 有一个密钥库 并且在通道确认用户使用该通道 MSP 后 CA何时参与 None
  • 查询字符串是否有类似 hashchange 的事件?

    我一直在使用哈希值在页面之间传递数据 例如设置scrollTop 等 并且还使用了hashChange触发给定页面上的更改的事件 然而 哈希值具有我不一定感兴趣的默认行为 例如使页面跳转到给定的 有时是无关紧要的 位置 我觉得获取 设置查询
  • 游戏路径寻找

    所有类型的游戏中都使用哪些路径查找算法 无论如何 在角色移动的所有类型中 迪杰斯特拉 Dijkstra 曾经被使用过吗 我并不是真的想编写任何代码 只是做一些研究 不过如果你粘贴伪代码或其他东西 那就没问题了 我可以理解 Java 和 C
  • Spyder互动剧情:等待剧情关闭继续

    我使用 Spyder 在 Windows 上工作 使用 matplotlib 进行绘图 我的问题是我想要进行交互式绘图 或者有时绘制很多东西 并且我希望spyder等待我关闭图形以继续代码 与传统终端相同的方式 我试过 plt ion mp
  • Linux 中的堆栈内存管理

    我有几个与 Linux 堆栈大小限制相关的问题 我对 x86 64 系统最感兴趣 但如果存在平台差异 我也想了解它们 我的问题是 1 Linux如何动态增加堆栈的大小 我编写了一个带有递归函数 以使用堆栈空间 的测试程序 我可以在其中指定迭
  • 在 Django 中,如何覆盖“保存并继续”功能?

    我需要向 ModelAdmin 添加一些保存前和保存后逻辑 但仅当用户通过 保存并继续编辑 按钮而不是 保存 按钮提交表单时 我怎样才能做到这一点 就像重写普通的保存方法一样 您需要重写save model ModelAdmin 中的函数
  • 将所有相对 URL 替换为绝对 URL

    我看过一些答案 比如this one https stackoverflow com questions 31347340 convert all relative urls to absolute urls while maintaini