PHP技巧:如何将相对URL转换为绝对URL
Haojinghui
・19 分钟阅读
绝对URL是完整的,可用于下载网站文件,但是,网页通常包含不完整的相对URL,缺少部分,如"http "或主机名,或文件路径的第一部分,需要通过从基本绝对URL复制它们来填充这些部分,本文展示了如何和包含代码来实现它。
介绍
一个类似于"http://example.com/index.htm
"的绝对URL告诉web浏览器哪些文件获得(index.htm
"" ),从哪里获取(来自example.com
"" ),如何获取(通过http网络服务器),但是,像logo.png
这样的相对URL缺少重要部分,如http
,主机名和路径的第一部分,没有这些部分,URL就不能用来获取文件。
使用相对URL,你必须通过从另一个URL复制它们来填充缺失的部分,这个URL或基本URL必须是绝对的,它通常是包含相对URL的网页的URL ,基本URL也可以由页面内的标记设置,通过服务器响应header中的Content-Location
字段和(很少)特殊的标记。
URL规范定义了一个"absolutize "算法来组合绝对基URL和相对URL来创建新的绝对URL ,本文介绍了算法的步骤,并在PHP中实现。
下面的代码需要来自一条辅助文章的split_url( )
和join_url( )
函数:
PHP提示:如何解析和生成URLs , 将URL分解成它们的组件部分,然后将这些部分重新组装成一个完整的URL 。
代码
让我们先直接进入代码,后续部分中的解释。
函数的url_to_absolute( )
参数包括绝对基URL和相对URL ,相对URL的缺少部分从基URL复制,以形成函数返回的一个新的绝对URL ,如果两个URL不能解析,或者基URL不是绝对的,则返回FALSE
。
functionurl_to_absolute($baseUrl,$relativeUrl){// If relative URL has a scheme, clean path and return.$r=split_url($relativeUrl);if($r===FALSE)returnFALSE;if(!empty($r['scheme'])){if(!empty($r['path'])&&$r['path'][0]=='/')$r['path']=url_remove_dot_segments($r['path']);returnjoin_url($r);} // Make sure the base URL is absolute.$b=split_url($baseUrl);if($b===FALSE||empty($b['scheme'])||empty($b['host']))returnFALSE;$r['scheme']=$b['scheme']; // If relative URL has an authority, clean path and return.if(isset($r['host'])){if(!empty($r['path']))$r['path']=url_remove_dot_segments($r['path']);returnjoin_url($r);}unset($r['port']);unset($r['user']);unset($r['pass']); // Copy base authority.$r['host']=$b['host'];if(isset($b['port']))$r['port']=$b['port'];if(isset($b['user']))$r['user']=$b['user'];if(isset($b['pass']))$r['pass']=$b['pass']; // If relative URL has no path, use base pathif(empty($r['path'])){if(!empty($b['path']))$r['path']=$b['path'];if(!isset($r['query'])&&isset($b['query']))$r['query']=$b['query'];returnjoin_url($r);} // If relative URL path doesn't start with /, merge with base pathif($r['path'][0]!='/'){$base=mb_strrchr($b['path'],'/',TRUE,'UTF-8');if($base===FALSE)$base='';$r['path']=$base.'/'.$r['path'];}$r['path']=url_remove_dot_segments($r['path']);returnjoin_url($r);}
url_remove_dot_segments(函数参数的唯一值是筛选的路径,返回筛选的路径。
functionurl_remove_dot_segments($path){// multi-byte character explode$inSegs=preg_split('!/!u',$path);$outSegs=array();foreach($inSegsas$seg){if($seg==''||$seg=='.')continue;if($seg=='..')array_pop($outSegs);elsearray_push($outSegs,$seg);}$outPath=implode('/',$outSegs);if($path[0]=='/')$outPath='/'.$outPath;// compare last multi-byte character against '/'if($outPath!='/'&&(mb_strlen($path)-1)==mb_strrpos($path,'/','UTF-8'))$outPath.='/';return$outPath;}
范例
合并基本URL和相对URL :
$newUrl=url_to_absolute("http://example.com/products/index.htm","./product.png");print("$newUrln");
打印:
http://example.com/products/product.png
从网页中提取网址,并且将每个网址转换为绝对网址(请参阅有关如何从网页中为extract_html_urls提取网址的文章)
// Get the web page text$text=file_get_contents($baseUrl);// Extract URLs and convert to a single list$groupedUrls=extract_html_urls($text);$pageUrls=array();foreach($urlsas$element_entry)foreach($element_entryas$attribute_entry)$pageUrls=array_merge($pageUrls,$attribute_entry);// Convert each URL to absolute$n=count($pageUrls);for($i=0;$i<$n;$i++)$pageUrls[$i]=url_to_absolute($baseUrl,$pageUrls[$i]);
说明
我们熟悉的URL格式由Internet Engineering Task Force在规范 RFC3986中正式定义,就像这个(括号内的部分是可选的):
[scheme ":"] scheme-specific-part ["?"query ]["#"fragment ]
例如在此URL中:
http://example.com/products/index.htm?sku=1234#section42
"http
"是方案,"//example.com/products/index.htm
"是scheme-specific-part,"sku=1234
"是查询,"section42
"是fragment 。
Internet分配的数字机构(IANA )有60个不同的URL方案,包括"http ","ftp ","file ",","
这个scheme-specific-part只是一个特定于—的方案,不同的方案期望不同的信息,例如,"http "方案的文件路径,"mailto"方案的电子邮件地址。
URL的查询部分通常包含数据库查询的参数,格式没有标准化,因此网站可以根据需要定义查询。
URL末尾的fragment通常是内容部分的名称,对于网页,这是页上锚的名称,它通常用来标记页面的各个部分。
所有方案可分为两种类型: 分层和非分层(也称为不透明),方案的分层scheme-specific-part包含一个通过斜线分隔的一系列单词的路径,对于诸如http http这样的方案,此路径通常选择一个文件,比如,/products/index.htm
",但是,非分层方案的URL包含其他信息,例如,"mailto "方案的电子邮件地址。
对于本文,我们只关心"http ","ftp "和"file "等层次结构,非分层方案不能具有相对URL。
因此,对于分层架构,scheme-specific-part包含一条路径,前面有一个这样的权限:
[ scheme ":"] ["//" authority ] [ path ] ["?" query ] ["#" fragment ]
部分的权限格式为:
[ user [":" pass ] "@"] host [":" port ]
权限包括主机名或IP地址(v4或v6 ),可以选择,主机后面有一个端口号(80用于网络服务器),一些方案支持前面的用户名和密码,但是,这是罕见的(而且在url中包含密码也不是很安全)。
绝对URL总是有一个方案,它通常有一个权限和路径,相对URL没有方案,它可能丢失了一些URL的其他部分或所有其他部分,如果相对URL的路径不以斜线开头,那么它也丢失了路径的第一部分。
当然,本文的重点是如何填充相对URL的缺失部分,使它成为绝对URL 。
绝对化一个相对url
如果缺少相对URL的部分,RFC3986规范将解释如何从绝对基URL复制它们,通常,基本URL是包含相对URL的网页的URL ,有几种其他方法可以获取基本URL :
- 在下载页面时,在Web服务器的HTTP标头中:
Content-Location
字段包含基本URL ,
- 在网页的网页部分:
- 标记字段的可选
href
包含基本URL , - 标记属性的可选
http-equiv
可能包含包含基本URL的Content-Location
字段,
- 标记字段的可选
- 在网页的网页正文中:
- 一个
- 一个