我需要一个函数,它可以接收相对URL和基本URL,并返回绝对URL。我已经搜索并找到了很多不同方法实现此功能的函数。
resolve("../abc.png", "http://example.com/path/thing?foo=bar")
# returns http://example.com/abc.png
有没有一种固定的方法?
在这个网站上,我看到了很棒的Python和C#示例,让我们来一个PHP的解决方案。
我需要一个函数,它可以接收相对URL和基本URL,并返回绝对URL。我已经搜索并找到了很多不同方法实现此功能的函数。
resolve("../abc.png", "http://example.com/path/thing?foo=bar")
# returns http://example.com/abc.png
有没有一种固定的方法?
在这个网站上,我看到了很棒的Python和C#示例,让我们来一个PHP的解决方案。
<?php
function rel2abs($rel, $base)
{
/* return if already absolute URL */
if (parse_url($rel, PHP_URL_SCHEME) != '' || substr($rel, 0, 2) == '//') return $rel;
/* queries and anchors */
if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
/* parse base URL and convert to local variables:
$scheme, $host, $path */
extract(parse_url($base));
/* remove non-directory element from path */
$path = preg_replace('#/[^/]*$#', '', $path);
/* destroy path if relative url points to root */
if ($rel[0] == '/') $path = '';
/* dirty absolute URL */
$abs = "$host$path/$rel";
/* replace '//' or '/./' or '/foo/../' with '/' */
$re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
/* absolute URL is ready! */
return $scheme.'://'.$abs;
}
?>
如果您已经使用GuzzleHttp,可以使用另一种解决方案。
这个解决方案基于GuzzleHttp\Client
的内部方法。
use GuzzleHttp\Psr7\UriResolver;
use GuzzleHttp\Psr7\Utils;
function resolve(string $uri, ?string $base_uri): string
{
$uri = Utils::uriFor(trim($uri));
if (isset($base_uri)) {
$uri = UriResolver::resolve(Utils::uriFor(trim($base_uri)), $uri);
}
// optional: set default scheme if missing
$uri = $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
return (string)$uri;
}
编辑:根据myriacl的建议,源代码已经更新。
if (isset($base_uri)) {
$uri = UriResolver::resolve( Utils::uriFor($base_uri), $uri);
}
// 可选:如果缺少默认协议,则设置默认协议
$uri = $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
return (string) $uri;
}
` - myriacl<?php
$url_parts = parse_url($relative_url);
$absolute = http_build_url($source_url, $url_parts, HTTP_URL_JOIN_PATH);
Ex:
<?php
function getAbsoluteURL($source_url, $relative_url)
{
$url_parts = parse_url($relative_url);
return http_build_url($source_url, $url_parts, HTTP_URL_JOIN_PATH);
}
echo getAbsoluteURL('http://foo.tw/a/b/c', '../pic.jpg') . "\n";
// http://foo.tw/a/pic.jpg
echo getAbsoluteURL('http://foo.tw/a/b/c/', '../pic.jpg') . "\n";
// http://foo.tw/a/b/pic.jpg
echo getAbsoluteURL('http://foo.tw/a/b/c/', 'http://bar.tw/a.js') . "\n";
// http://bar.tw/a.js
echo getAbsoluteURL('http://foo.tw/a/b/c/', '/robots.txt') . "\n";
// http://foo.tw/robots.txt
http_build_url
方法是 PECL 扩展的一部分,该扩展未捆绑在 PHP 中。 - mpenpecl install pecl_http-1.7.6
- KTB这里有另一个处理协议相对URL的函数。
<?php
function getAbsoluteURL($to, $from = null) {
$arTarget = parse_url($to);
$arSource = parse_url($from);
$targetPath = isset($arTarget['path']) ? $arTarget['path'] : '';
if (isset($arTarget['host'])) {
if (!isset($arTarget['scheme'])) {
$proto = isset($arSource['scheme']) ? "{$arSource['scheme']}://" : '//';
} else {
$proto = "{$arTarget['scheme']}://";
}
$baseUrl = "{$proto}{$arTarget['host']}" . (isset($arTarget['port']) ? ":{$arTarget['port']}" : '');
} else {
if (isset($arSource['host'])) {
$proto = isset($arSource['scheme']) ? "{$arSource['scheme']}://" : '//';
$baseUrl = "{$proto}{$arSource['host']}" . (isset($arSource['port']) ? ":{$arSource['port']}" : '');
} else {
$baseUrl = '';
}
$arPath = [];
if ((empty($targetPath) || $targetPath[0] !== '/') && !empty($arSource['path'])) {
$arTargetPath = explode('/', $targetPath);
if (empty($arSource['path'])) {
$arPath = [];
} else {
$arPath = explode('/', $arSource['path']);
array_pop($arPath);
}
$len = count($arPath);
foreach ($arTargetPath as $idx => $component) {
if ($component === '..') {
if ($len > 1) {
$len--;
array_pop($arPath);
}
} elseif ($component !== '.') {
$len++;
array_push($arPath, $component);
}
}
$targetPath = implode('/', $arPath);
}
}
return $baseUrl . $targetPath;
}
// SAMPLES
// Absolute path => https://www.google.com/doubleclick/
echo getAbsoluteURL('/doubleclick/', 'https://www.google.com/doubleclick/insights/') . "\n";
// Relative path 1 => https://www.google.com/doubleclick/studio
echo getAbsoluteURL('../studio', 'https://www.google.com/doubleclick/insights/') . "\n";
// Relative path 2 => https://www.google.com/doubleclick/insights/case-studies.html
echo getAbsoluteURL('./case-studies.html', 'https://www.google.com/doubleclick/insights/') . "\n";
// Relative path 3 => https://www.google.com/doubleclick/insights/case-studies.html
echo getAbsoluteURL('case-studies.html', 'https://www.google.com/doubleclick/insights/') . "\n";
// Protocol relative url => https://www.google.com/doubleclick/
echo getAbsoluteURL('//www.google.com/doubleclick/', 'https://www.google.com/doubleclick/insights/') . "\n";
// Empty path => https://www.google.com/doubleclick/insights/
echo getAbsoluteURL('', 'https://www.google.com/doubleclick/insights/') . "\n";
// Different url => http://www.yahoo.com/
echo getAbsoluteURL('http://www.yahoo.com/', 'https://www.google.com') . "\n";
已经链接在pguardiario评论中的其他工具:http://publicmind.in/blog/urltoabsolute/,https://github.com/monkeysuffrage/phpuri。
我在http://nadeausoftware.com/articles/2008/05/php_tip_how_convert_relative_url_absolute_url的评论中发现了其他工具:
require_once 'Net/URL2.php';
$base = new Net_URL2('http://example.org/foo.html');
$absolute = (string)$base->resolve('relative.html#bar');
function absoluteUri($Path, $URI)
{ # Requires PHP4 or better.
$URL = parse_url($URI);
$Str = "{$URL['scheme']}://";
if (isset($URL['user']) || isset($URL['pass']))
$Str .= "{$URL['user']}:{$URL['pass']}@";
$Str .= $URL['host'];
if (isset($URL['port']))
$Str .= ":{$URL['port']}";
$Str .= realpath($URL['path'] . $Path); # This part might have an issue on windows boxes.
if (isset($URL['query']))
$Str .= "?{$URL['query']}";
if (isset($URL['fragment']))
$Str .= "#{$URL['fragment']}";
return $Str;
}
absoluteUri("../abc.png", "http://example.com/path/thing?foo=bar");
# Should return "http://example.com/abc.png?foo=bar" on Linux boxes.
我注意到上面的点赞答案使用了正则表达式,但在处理URL时可能会存在危险。
此函数将解析相对URL到$pgurl
给定的当前页面URL无需正则表达式。它成功地解析了:
/home.php?example
类型,
同一目录下的 nextpage.php
类型,
../...../.../parentdir
类型,
完整的 http://example.net
URL,
以及简写的 //example.net
URL。
//Current base URL (you can dynamically retrieve from $_SERVER)
$pgurl = 'http://example.com/scripts/php/absurl.php';
function absurl($url) {
global $pgurl;
if(strpos($url,'://')) return $url; //already absolute
if(substr($url,0,2)=='//') return 'http:'.$url; //shorthand scheme
if($url[0]=='/') return parse_url($pgurl,PHP_URL_SCHEME).'://'.parse_url($pgurl,PHP_URL_HOST).$url; //just add domain
if(strpos($pgurl,'/',9)===false) $pgurl .= '/'; //add slash to domain if needed
return substr($pgurl,0,strrpos($pgurl,'/')+1).$url; //for relative links, gets current directory and appends new filename
}
function nodots($path) { //Resolve dot dot slashes, no regex!
$arr1 = explode('/',$path);
$arr2 = array();
foreach($arr1 as $seg) {
switch($seg) {
case '.':
break;
case '..':
array_pop($arr2);
break;
case '...':
array_pop($arr2); array_pop($arr2);
break;
case '....':
array_pop($arr2); array_pop($arr2); array_pop($arr2);
break;
case '.....':
array_pop($arr2); array_pop($arr2); array_pop($arr2); array_pop($arr2);
break;
default:
$arr2[] = $seg;
}
}
return implode('/',$arr2);
}
使用示例:
echo nodots(absurl('../index.html'));
nodots()
必须在将 URL 转换为绝对路径后调用。
虽然 dots 函数有些多余,但它易读、快速、不使用正则表达式,并且可以解析 99% 的典型 URL(如果您想要确保百分之百,请将 switch 块扩展到支持 6+ 个点,尽管我从未见过 URL 中有那么多点)。
希望这可以帮助到您,