相信很多程序(尤其是采集类的程序)都会有需要把网址的相对路径转换成绝对路径的需要,例如采集到某页面的HTML代码中包含资源文件经常会看到这样的文件名:

  • <link rel="stylesheet" href="css/style.css" />
  • <img src="/logo.png" />
  • <img src="../banner.jpg" />

如果直接用获取其href属性或src属性很明显这个地址是打不开的,这就需要将其中的相对路径转为绝对路径。查一下网上相关的代码也不少,但大多数代码都太难被读懂,而且执行效率不见得会高,基于此我开始着手写一个自己的转化方法。

由于采集来的网址格式大部分为绝对地址或者位于根目录的地址,所以代码对这两种格式的的地址优先处理并返回,以提高代码的执行效率。

源码如下:函数接收两个参数,第一个参数为采集到的相对路径,第二个参数为被采集的原始的URL,例如从www.example.com/a/b/c.html中采集到某资源地址为css/style.css,那么函数调用方式为filter_relative_url('css/style.css', 'http://www.example.com/a/b/c.html');(注:函数中省略了对URI参数的验证和过滤操作,如果URI参数没加http://前缀会报错,相关验证代码可自行添加)。

  • /**
  • * 把从HTML源码中获取的相对路径转换成绝对路径
  • * @param string $url HTML中获取的网址
  • * @param string $URI 用来参考判断的原始地址
  • * @return 返回修改过的网址,如果网址有误则返回FALSE
  • */
  • function filter_relative_url($url, $URI){
  • //STEP1: 先去判断URL中是否包含协议,如果包含说明是绝对地址则可以原样返回
  • if(strpos($url, '://') !== FALSE){
  • return $url;
  • }
  • //STEP2: 解析传入的URI
  • $URI_part = parse_url($URI);
  • if($URI_part == FALSE)
  • return FALSE;
  • $URI_root = $URI_part['scheme'] . '://' . $URI_part['host'] . (isset($URI_part['port']) ? ':' . $URI_part['port'] : '');
  • //STEP3: 如果URL以左斜线开头,表示位于根目录
  • if(strpos($url, '/') === 0){
  • return $URI_root . $url;
  • }
  • //STEP4: 不位于根目录,也不是绝对路径,考虑如果不包含'./'的话,需要把相对地址接在原URL的目录名上
  • $URI_dir = (isset($URI_part['path']) &amp;&amp; $URI_part['path']) ? '/' . ltrim(dirname($URI_part['path']), '/') : '';
  • if(strpos($url, './') === FALSE){
  • if($URI_dir != ''){
  • return $URI_root . $URI_dir . '/' . $url;
  • } else {
  • return $URI_root . '/' . $url;
  • }
  • }
  • //STEP5: 如果相对路径中包含'../'或'./'表示的目录,需要对路径进行解析并递归
  • //STEP5.1: 把路径中所有的'./'改为'/','//'改为'/'
  • $url = preg_replace('/[^\.]\.\/|\/\//', '/', $url);
  • if(strpos($url, './') === 0)
  • $url = substr($url, 2);
  • //STEP5.2: 使用'/'分割URL字符串以获取目录的每一部分进行判断
  • $URI_full_dir = ltrim($URI_dir . '/' . $url, '/');
  • $URL_arr = explode('/', $URI_full_dir);
  • if($URL_arr[0] == '..')
  • return FALSE;
  • //因为数组的第一个元素不可能为'..',所以这里从第二个元素开始循环
  • $dst_arr = $URL_arr; //拷贝一个副本,用于最后组合URL
  • for($i = 1; $i < count($URL_arr); $i ++){
  • if($URL_arr[$i] == '..'){
  • $j = 1;
  • while(TRUE){
  • if(isset($dst_arr[$i - $j]) &amp;&amp; $dst_arr[$i - $j] != FALSE){
  • $dst_arr[$i - $j] = FALSE;
  • $dst_arr[$i] = FALSE;
  • break;
  • } else {
  • $j ++;
  • }
  • }
  • }
  • }
  • // 组合最后的URL并返回
  • $dst_str = $URI_root;
  • foreach($dst_arr as $val){
  • if($val != FALSE)
  • $dst_str .= '/' . $val;
  • }
  • return $dst_str;
  • }
php

代码如上分为几步针对不同格式的相对路径进行处理并返回,以下是测试代码:

  • $URI_1 = 'http://www.abc.com/a/b/c/d.html';
  • $URI_2 = 'http://www.abc.com';
  • $test [] = 'http://www.abc.com/css/style.css';
  • $test [] = '/img/banner.jpg';
  • $test [] = 'images/res_03.png';
  • $test [] = '../../js/jquery.min.js';
  • $test [] = './../res/js/../jquery/./1.8.3/jquery.js';
  • foreach($test as $val){
  • echo filter_relative_url($val, $URI_1);
  • }
  • foreach($test as $val){
  • echo filter_relative_url($val, $URI_2);
  • }
php

程序返回:

  • http://www.abc.com/css/style.css
  • http://www.abc.com/img/banner.jpg
  • http://www.abc.com/a/b/c/images/res_03.png
  • http://www.abc.com/a/js/jquery.min.js
  • http://www.abc.com/a/b/res/jquery/1.8.3/jquery.js
  • http://www.abc.com/css/style.css
  • http://www.abc.com/img/banner.jpg
  • http://www.abc.com/images/res_03.png

*注:测试代码的第二个循环只返回了3条结果,是因为后两条结果返回了FALSE,因为原始URI是位于网站根目录,再在前面加“../“请求上级目录是无效的。

以上代码的主要优点是解决了网上流传的那些代码对于复杂格式的相对路径不能完美兼容的问题,同时照顾了执行效率,减少判断和分解的次数。此代码目前我自己正在使用,如果有任何问题还请留言或邮件联系我,谢谢!


2016年5月17日更新

看到PHP官网WIKI上面有一个关于相对地址转换的写法,写在下面以供参考:

  • function normalizePath($path)
  • {
  • $parts = array();// Array to build a new path from the good parts
  • $path = str_replace('\\', '/', $path);// Replace backslashes with forwardslashes
  • $path = preg_replace('/\/+/', '/', $path);// Combine multiple slashes into a single slash
  • $segments = explode('/', $path);// Collect path segments
  • $test = '';// Initialize testing variable
  • foreach($segments as $segment)
  • {
  • if($segment != '.')
  • {
  • $test = array_pop($parts);
  • if(is_null($test))
  • $parts[] = $segment;
  • else if($segment == '..')
  • {
  • if($test == '..')
  • $parts[] = $test;
  • if($test == '..' || $test == '')
  • $parts[] = $segment;
  • }
  • else
  • {
  • $parts[] = $test;
  • $parts[] = $segment;
  • }
  • }
  • }
  • return implode('/', $parts);
  • }
php

参考资料:

本文链接:https://icewing.cc/post/php-conv-addr-re-ab-2.html

黄聪:PHP转换网址相对路径到绝对路径的一种方法的更多相关文章

  1. WPF编程,通过Path类型制作沿路径运动的动画另一种方法。

    原文:WPF编程,通过Path类型制作沿路径运动的动画另一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/d ...

  2. filebeat配置不同路径下的log的两种方法

    第一种方法: vim /etc/filebeat/filebeat.yml filebeat.inputs: # Each - is an input. Most options can be set ...

  3. Java从文件路径中获取文件名的几种方法

    举例:String fName =" G:\Java_Source\navigation_tigra_menu\demo1\img\lev1_arrow.gif " 方法一: 1 ...

  4. python将字符串转换成字典的几种方法

    当我们遇到类似于{‘a’:1, 'b':2, 'c':3}这种字符串时,想要把它转换成字典进行处理,可以使用以下几种方法: 1. Python自带的eval函数(不安全) dictstr = '{&q ...

  5. 如何修改myeclipse中web项目的工作路径或默认路径

    如何修改myeclipse中web项目的工作路径或默认路径 博客分类: J2EE开发技术指南   安装好myeclipse后,第一次启动myeclipse时,都会弹出会弹出Workspace Laun ...

  6. 黄聪:如何使用CodeSmith批量生成代码(转:http://www.cnblogs.com/huangcong/archive/2010/06/14/1758201.html)

    先看看CodeSmith的工作原理: 简单的说:CodeSmith首先会去数据库获取数据库的结构,如各个表的名称,表的字段,表间的关系等等,之后再根据用户自定义好的模板文件,用数据库结构中的关键字替代 ...

  7. 【转】黄聪:HtmlAgilityPack教程案例

    [转]黄聪:HtmlAgilityPack教程案例 HtmlAgilityPack中的HtmlNode类与XmlNode类差不多,提供的功能也大同小异.下面来看看该类提供功能. 一.静态属性 publ ...

  8. 黄聪:《跟黄聪学WordPress插件开发》

    续<跟黄聪学WordPress主题开发>之后,又一个作品完成!<跟黄聪学Wordpress插件开发>,国内最好的Wordpress插件开发视频教程!! 目录预览: WordPr ...

  9. C# .Net实现URL绝对路径和相对路径之间互相转换

    网站制作开发中,URL的绝对路径和相对路径之间互相转换,是经常需要用到的.以下是在C#.Net下一种实现二者互相转化的方法: [DllImport("shlwapi.dll", C ...

随机推荐

  1. 如何清除Mac上的空间,让Mac更有效地运行

    清理Mac上的空间通常被认为是一件必须要做的事情.因为这样,Mac将在驱动器上具有更多可用空间,从而可以更好地运行,并且您(以及系统和各种应用程序)可以根据需要利用额外的空间. 您可能会问的一个问题是 ...

  2. 07-Node.js学习笔记-路由

    路由 http://localhost:3000/index http://localhost:3000/login //路由是指客户端请求地址与服务器端程序代码的对应关系.简单的说,就是请求什么响应 ...

  3. win 10 命令行导出注册表

    命令如下: reg  export  注册表中的key  保存路径 reg export HKLM\Software\MyCo\MyApp AppBkUp.reg 如果需要直接覆盖原来的文件,可以加上 ...

  4. JavaScript-----14.内置对象 Array()和String()

    5. 数组对象 5.1数组的创建 之前提到过数组的创建方式 字面量 new Array() //创建数组的两种方式 //1.利用数组字面量 var arr = [1, 2, 3]; console.l ...

  5. swoole为什么不能代替nginx

    Swoole不能代替Apache和Nginx这些通用的HTTP服务器. 但基于Swoole开发的PHP应用不依赖Apache和Nginx也能提供生产级别的HTTP服务. 有需要学习交流的友人请加入交流 ...

  6. python之字符串的拼接总结

    加号连接 1.通过+号连接起来 逗号连接 2.通过都好连接起来 但是,这里值得注意的是,只能用于print打印,赋值组操作会生成元组 直接连接 3.直接连接中间有无空格均可 %连接 在python2. ...

  7. 02-Nginx配置

    一.Nginx配置 1.创建Nginx运行使用的用户 www: / usr / sbin / groupadd www / usr / sbin / useradd -g www www 2.检查配置 ...

  8. linux中网络配置

    一.查看ip ipconfig 二.png 测试主机之间网络连通 ping 目标ip #测试当前服务器是否可以连接目的主机 三.linux配置网络环境 vim /etc/sysconfig/netwo ...

  9. CAD转DXF怎么转换?教你三种转换方法

    CAD图纸在我们日常生活中都是可见到的,因为CAD图纸文件的格式是多样的,在工作中就需要经常将CAD的格式进行转换.那CAD转DXF怎么转换呢?这个问题很多的小伙伴们都遇到过,下面小编就来教大家三种转 ...

  10. vscode自动修复eslint规范的插件及配置

    在开发大型项目中,经常都是需要多人合作的.相信大家一定都非常头疼于修改别人的代码的吧,而合理的使用eslint规范可以让我们在代码review时变得轻松,也可以让我们在修改小伙伴们的代码的时候会更加清 ...