正则表达式只匹配本地URL以用于phpbb

时间:2012-08-16 22:00:08

标签: php regex phpbb3

我正在使用phpBB3制作留言板。内置功能可以将帖子中的所有URL和呈现作为链接。我想做到这一点,只有本地链接可以点击。

phpbb3在帖子的文本中使用正则表达式,并且对于每个匹配将其更改为链接:

if ($somestuff){
// matches a xxxx://aaaaa.bbb.cccc. ...
$magic_url_match[] = '#(^|[\n\t (>.])(' . "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#ie';
$magic_url_replace[] = "make_clickable_callback(MAGIC_URL_FULL, '\$1', '\$2', '', '$class')";

// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
$magic_url_match[] = '#(^|[\n\t (>])(' . "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#ie';
$magic_url_replace[] = "make_clickable_callback(MAGIC_URL_WWW, '\$1', '\$2', '', '$class')";
}
return preg_replace($magic_url_match, $magic_url_replace, $text);

如何重写这些正则表达式,以便它们只匹配我的域上的链接?另外,教自己正则表达式的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

这是第一个,逐节分解。即使这样做也是非常重要的......

(
    ^
|
    [\n\t (>.]
)

好的,这里我们只是“行的开头,或换行符,制表符,空格,大于,句号。只需锚定正则表达式。

(
    [a-z]$scheme*:/{2}

这是纯粹的疯狂。 $scheme可能会保留http,这意味着此正则表达式与http://匹配。为什么有人会使用/{2}代替//,我无法开始猜测。

    (?:
        (?:
            [a-z0-9\-._~!$&'($inline*+,;=:@|]+
        |
            %[\dA-F]{2}
        )+
    |

这匹配了一系列字符,可能是那些在URL中合法的字符。值得注意的是$inline PHP变量 - 不能猜测它的含义 - 以及第二个替代%[\dA-F]{2}。对于空格等匹配%20之类的内容等。%符号在匹配(或URL)中不合法。

此处同样重要的是/不合法。因此,这不能引用目录,只能引用域。这很可能是您想要更改的部分,只需匹配您网站的相应域。

为了完整起见,这是剩下的。

        [0-9.]+
    |

或者,我们可以有一系列数字和句点 - 一个IP地址。考虑到这个正则表达式有多复杂,我很惊讶他没有去(?:\d{1,3}\.){3}\d{1,3} ...

        \[
        [a-z0-9.]+
        :
        [a-z0-9.]+
        :
        [a-z0-9.:]+
        \]
    )

这是我们的最后一个选择;我认为这是针对IPv6的。无论如何,它是由冒号分隔的一系列十六进制数字。它要求它们在方括号内,我觉得很奇怪,特别是对于那些如此大量使用标签的论坛软件......

    (?:
        :
        \d*
    )?

在这里,我们得到冒号后面的一些数字选项。也就是说,这适用于包含端口的URL。

    (?:
        /
        (?:
            [a-z0-9\-._~!$&'($inline*+,;=:@|]+
        |
            %[\dA-F]{2}
        )*
    )*

好的,这里我们已经到了子目录,如开头的/所示。否则,这是相同的“合法网址字符”匹配。

    (?:
        \?
        (?:
            [a-z0-9\-._~!$&'($inline*+,;=:@/?|]+
        |
            %[\dA-F]{2}
        )*
    )?
    (?:
        \#
        (?:
            [a-z0-9\-._~!$&'($inline*+,;=:@/?|]+
        |
            %[\dA-F]{2}
        )*
    )?
)

最后,由GET表示的\?传递的内容以及链接到中间页锚点的网址由\#表示。

底线:

本节:

    [a-z]$scheme*:/{2}
    (?:
        (?:
            [a-z0-9\-._~!$&'($inline*+,;=:@|]+
        |
            %[\dA-F]{2}
        )+
    |
        [0-9.]+
    |
        \[
        [a-z0-9.]+
        :
        [a-z0-9.]+
        :
        [a-z0-9.:]+
        \]
    )

应该替换为这样的东西:

    [a-z]$scheme*://
    www\.example\.com

或者

    [a-z]$scheme*://
    (?:
        www\.example\.com
    |
        192\.168\.0\.1
    |
        ::ffff:192\.168\.0\.1
    )

域名和IP地址与您的网站匹配。显然,你将不得不删除我所做的换行符和缩进。我会为你做的,但我认为这几乎是不值得的,因为你很难找到你把你的域放在所有那些中间的地方。

您可能希望为子域名或者遗漏www.的人或者有你的人提供一些正则表达式。

您可能还想删除此内容:

    (?:
        :
        \d*
    )?

因为您可能不希望人们链接到您域中的其他端口。

第二个看起来具有大致相同的结构;正如评论所说,它只是让URL缺少协议指示符。