PHP:查找输出中的相对路径图片和链接,并将它们转换为绝对路径

9

有很多关于在PHP中将相对路径转换为绝对路径的文章。我正在寻找超越这些文章的特定实现(希望如此)。请问有谁能帮我完成这个具体实现吗?

我有一个包含各种HTML内容的PHP变量,包括包含相对URL的hrefimg。大多数情况下(例如)/en/discover/img/icons/facebook.png

我想要以这样一种方式处理这个PHP变量,即我的hrefimg的值将被转换为http://mydomain.com/en/discoverhttp://mydomain.com/img/icons/facebook.png

我认为下面的问题涵盖了解决href的方案。我们如何将其扩展到考虑img呢?

需要使用正则表达式吗?还是因为我们要处理大量输出,应该使用DOMDocument?


而且在您的<head>中使用<base href="http://mydomain.com">不就足够了吗?如果不行,那么使用正则表达式是您唯一能做的事情 - 实际上您需要使用preg_replace_all函数。 - shadyyx
谢谢您的回复。好建议,但我不这么认为,因为输出将显示在XML文档中。问题是我对正则表达式无能为力... - chocolata
3个回答

9

经过进一步的研究,我偶然发现了Gerd Riesselmann关于如何解决RSS feeds中缺少base href解决方案的文章。 他的代码片段实际上解决了我的问题!

http://www.gerd-riesselmann.net/archives/2005/11/rss-doesnt-know-a-base-url

<?php
function relToAbs($text, $base)
{
  if (empty($base))
    return $text;
  // base url needs trailing /
  if (substr($base, -1, 1) != "/")
    $base .= "/";
  // Replace links
  $pattern = "/<a([^>]*) " .
             "href=\"[^http|ftp|https|mailto]([^\"]*)\"/";
  $replace = "<a\${1} href=\"" . $base . "\${2}\"";
  $text = preg_replace($pattern, $replace, $text);
  // Replace images
  $pattern = "/<img([^>]*) " . 
             "src=\"[^http|ftp|https]([^\"]*)\"/";
  $replace = "<img\${1} src=\"" . $base . "\${2}\"";
  $text = preg_replace($pattern, $replace, $text);
  // Done
  return $text;
}
?>

谢谢您,Gerd!还要感谢shadyyx指引我使用base href


4

优秀的解决方案。 然而,在模式中有一个小错别字。按照上面的写法,它截断了 href 或 src 的第一个字符。这里提供符合预期的模式:

// Replace links
$pattern = "/<a([^>]*) " .
         "href=\"([^http|ftp|https|mailto][^\"]*)\"/";

并且

// Replace images
$pattern = "/<img([^>]*) " . 
         "src=\"([^http|ftp|https][^\"]*)\"/";

第二个替换引用的开头括号被移动了。这将会把href或src中第一个不匹配http|ftp|https的字符放入替换引用中。

谢谢,工作更好!只有以#开头的链接不应受影响。 使用[^http|ftp|https|mailto|#]可针对“#head1”起作用,但它应该将“mypage.html#head1”替换为完整的URL。 - Barryvdh

3
我发现,当href src和base url变得更加复杂时,被接受的答案解决方案对我不起作用。
例如:
基本网址:
http://www.journalofadvertisingresearch.com/ArticleCenter/default.asp?ID=86411&Type=Article
href src:
/ArticleCenter/LeftMenu.asp?Type=Article&FN=&ID=86411&Vol=&No=&Year=&Any=
错误返回:
/ArticleCenter/LeftMenu.asp?Type=Article&FN=&ID=86411&Vol=&No=&Year=&Any=
我找到了下面的函数,可以正确地返回URL。我从这里的评论中获得了这个函数: http://php.net/manual/en/function.realpath.php ,来自Isaac Z. Schlueter。
这样就能正确地返回:
http://www.journalofadvertisingresearch.com/ArticleCenter/LeftMenu.asp?Type=Article&FN=&ID=86411&Vol=&No=&Year=&Any=

function resolve_href ($base, $href) { 

// href="" ==> current url. 
if (!$href) { 
    return $base; 
} 

// href="http://..." ==> href isn't relative 
$rel_parsed = parse_url($href); 
if (array_key_exists('scheme', $rel_parsed)) { 
    return $href; 
} 

// add an extra character so that, if it ends in a /, we don't lose the last piece. 
$base_parsed = parse_url("$base "); 
// if it's just server.com and no path, then put a / there. 
if (!array_key_exists('path', $base_parsed)) { 
    $base_parsed = parse_url("$base/ "); 
} 

// href="/ ==> throw away current path. 
if ($href{0} === "/") { 
    $path = $href; 
} else { 
    $path = dirname($base_parsed['path']) . "/$href"; 
} 

// bla/./bloo ==> bla/bloo 
$path = preg_replace('~/\./~', '/', $path); 

// resolve /../ 
// loop through all the parts, popping whenever there's a .., pushing otherwise. 
    $parts = array(); 
    foreach ( 
        explode('/', preg_replace('~/+~', '/', $path)) as $part 
    ) if ($part === "..") { 
        array_pop($parts); 
    } elseif ($part!="") { 
        $parts[] = $part; 
    } 

return ( 
    (array_key_exists('scheme', $base_parsed)) ? 
        $base_parsed['scheme'] . '://' . $base_parsed['host'] : "" 
) . "/" . implode("/", $parts); 
} 

1
感谢您的贡献! - chocolata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接