PHP - 查找帖子中的所有超链接,添加目标和rel = nofollow属性

时间:2014-05-03 06:04:19

标签: php hyperlink attributes nofollow

我需要找到一种方法来阅读用户发布的内容,以查找可能已包含的任何超链接,创建锚标记,将target和rel = nofollow属性添加到所有这些链接。

我遇到过一些像这样的REGEX解决方案:

 (?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

但是在关于同一问题的其他问题上,强烈建议 NOT 使用REGEX而不是PHP的DOMDocument

无论什么是最好的方式,我需要添加一些如上所述的属性,以加强网站上的所有外部链接。

3 个答案:

答案 0 :(得分:1)

您可能对Goutte感兴趣 你可以定义自己的过滤器等。

答案 1 :(得分:1)

首先,您提到的指南建议不要使用正则表达式解析 HTML 。据我了解,您要做的是解析用户的纯文本并将其转换为HTML 。为此目的,正则表达式通常都很好。

(请注意,我假设您自己将文本解析为链接,并且不使用外部库。在后一种情况下,您需要修复HTML库输出,为此您< em>应使用DOMDocument迭代所有<a>标记并添加适当的属性。)

现在,您可以通过两种方式解析它:服务器端或客户端。

服务器端

优点:

  • 输出准备使用的HTML。
  • 它不要求用户启用Javascript。

缺点:

  • 您需要为机器人添加rel="nofollow"属性,以便不遵循链接。

客户端

优点:

  • 您不需要为机器人添加rel="nofollow"属性,因为他们首先看不到链接 - 他们是通过Javascript生成的,机器人通常不会#&# 39;解析Javascript。

缺点:

  • 以这种方式创建链接需要用户启用Javascript。
  • 在Javascript中实现这样的东西会让人觉得网站很慢,特别是如果要解析大量文本的话。
  • 它使缓存解析文本变得困难。

我将专注于在服务器端实施它。

服务器端实现

因此,为了解析用户输入的链接并添加任何您想要的属性,您可以使用以下内容:

<?php
function replaceLinks($text)
{
    $regex = '/'
      . '(?<!\S)'
      . '(((ftp|https?)?:?)\/\/|www\.)'
      . '(\S+?)'
      . '(?=$|\s|[,]|\.\W|\.$)'
      . '/m';

    return preg_replace_callback($regex, function($match)
    {
        return '<a'
          . ' target=""'
          . ' rel="nofollow"'
          . ' href="' . $match[0] . '">'
          . $match[0]
          . '</a>';
    }, $text);
}

说明:

  • (?<!\S):前面没有非空白字符。
  • (((ftp|https?)?:?)\/\/|www\.):接受ftp://http://https://:////www.作为网址的开头。
  • (\S+?)以非贪婪的方式匹配所有非空白的内容。
  • (?=$|\s|[,]|\.\W|\.$)每个网址必须跟在行尾,空格,逗号,点后跟\w以外的字符(这是为了允许.com,{{ 1}}等匹配)或点后跟行尾。
  • .co.jp flag - 匹配多行文字。

测试

现在,为了支持我声称它有效,我添加了一些测试用例:

m

每个测试用例由两部分组成:源输入和预期输出。我使用以下代码来确定函数是否通过了上述测试:

$tests = [];
$tests []= ['http://example.com', '<a target="" rel="nofollow" href="http://example.com">http://example.com</a>'];
$tests []= ['https://example.com', '<a target="" rel="nofollow" href="https://example.com">https://example.com</a>'];
$tests []= ['ftp://example.com', '<a target="" rel="nofollow" href="ftp://example.com">ftp://example.com</a>'];
$tests []= ['://example.com', '<a target="" rel="nofollow" href="://example.com">://example.com</a>'];
$tests []= ['//example.com', '<a target="" rel="nofollow" href="//example.com">//example.com</a>'];
$tests []= ['www.example.com', '<a target="" rel="nofollow" href="www.example.com">www.example.com</a>'];
$tests []= ['user@www.example.com', 'user@www.example.com'];
$tests []= ['testhttp://example.com', 'testhttp://example.com'];
$tests []= ['example.com', 'example.com'];
$tests []= [
    'test http://example.com',
    'test <a target="" rel="nofollow" href="http://example.com">http://example.com</a>'];
$tests []= [
    'multiline' . PHP_EOL . 'blah http://example.com' . PHP_EOL . 'test',
    'multiline' . PHP_EOL . 'blah <a target="" rel="nofollow" href="http://example.com">http://example.com</a>' . PHP_EOL . 'test'];
$tests []= [
    'text //example.com/slashes.php?parameters#fragment, some other text',
    'text <a target="" rel="nofollow" href="//example.com/slashes.php?parameters#fragment">//example.com/slashes.php?parameters#fragment</a>, some other text'];
$tests []= [
    'text //example.com. new sentence',
    'text <a target="" rel="nofollow" href="//example.com">//example.com</a>. new sentence'];

我认为这可以让您了解如何解决问题。随意添加更多测试并使用正则表达式进行实验,以使其适合您的特定需求。

答案 2 :(得分:0)

使用jquery获取要发布的内容并在将其发布到PHP之前对其进行处理。

$('#idof_content').val(
  $('#idof_content').val().replace(/\b(http(s|):\/\/|)(www\.\S+)/ig,
    "<a href='http\$2://\$3' target='_blank' rel='nofollow'>\$3</a>"));