php - PHP:使用标签、省略号和链接图标查找、替换、缩短和美化用户链接
6 回答
www.google.com
这不是 URL,而是主机名。在任意文本中开始标记裸主机名通常不是一个好主意,因为在一般情况下,任何单词或点分隔的单词序列都是完全有效的主机名。这意味着你会遇到可怕的黑客攻击,比如寻找领先的www.
(你会得到诸如“为什么我可以链接www.stackoverflow.com
但不能链接stackoverflow.com
?”)或尾随 TLD(随着更多新 TLD 的引入,这变得越来越不切实际;“为什么可以我喜欢 ncm.com 但不喜欢ncm.museum
?”),而且您经常会标记不应该是链接的内容。
我可以尝试写一些非常花哨的正则表达式
好吧,如果没有正则表达式,我看不出你会怎么做。
诀窍是处理标记。如果您可以在输入中包含<
,&
和"
字符,则不能让它们进入 HTML 输出。如果您的输入是纯文本,您可以通过htmlspecialchars()
在对像 nico 的答案那样的模式应用简单替换之前调用来做到这一点。
(如果输入已经包含标记,您就会遇到问题,您可能需要一个 HTML 解析器来确定哪些位是标记以避免在其中添加更多标记。同样,如果您在此之后进行更多处理,则插入更多标签,这些步骤可能具有相同的困难。在类似“bbcode”的语言中,这通常会导致错误和安全问题。)
另一个问题是尾随标点符号。人们通常在链接后加上句号、逗号、右括号、感叹号等,这些不应该是链接的一部分,但实际上是有效字符。将它们剥离而不是将它们放入链接中很有用。但是随后您破坏了以 结尾的 Wiki 链接,因此如果链接中有 a 或类似的东西,)
您可能不想将)
其视为尾随字符。(
这种事情不能在简单的正则表达式替换中完成,但您可以在替换回调函数中完成。
HTML Purifier有一个内置的链接功能,可以为您省去所有的麻烦。
如果您要处理还必须显示的任何类型的用户输入,那么它的其他功能也太有用了,不容忽视。
不是那么花哨的正则表达式应该可以工作
/\b(https?:\/\/[^\s+\"\<\>]+)/ig
/\b(www.[^\s+\"\<\>]+)/ig
请注意,最后两个无法正确执行,因为您无法将 google.com 与类似的内容区分开来。我完成一个句子并且在句号后不加空格。
至于缩短网址,请将您的网址放在$url
:
if (strlen($url) > 20) // Or whatever length you like
{
$shortURL = substr($url, 0, 20)."…";
}
else
{
$shortURL = $url;
}
echo '<a href="'.$url.'" >'.$shortURL.'</a>';
我在这里完全按照我想要的方式工作:
<?php
$input = <<<EOF
http://www.example.com/
http://example.com
www.example.com
http://iamanextremely.com/long/link/so/I/will/be/trimmed/down/a/bit/so/i/dont/mess
/up/text/wrapping.html
EOF;
function trimlong($match)
{
$url = $match[0];
$display = $url;
if ( strlen($display) > 30 ) {
$display = substr($display,0,30)."...";
}
return '<a href="'.$url.'">'.$display.' <img src="http://static.goalscdn.com/img/external-link.gif" height="10" width="11" /></a>';
}
$output = preg_replace_callback('#(http://|www\\.)[^\\s<]+[^\\s<,.]#i',
array($this,'trimlong'),$input);
echo $output;
来自http://www.exorithm.com/algorithm/view/markup_urls
function markup_urls ($text)
{
// split the text into words
$words = preg_split('/([\s\n\r]+)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$text = "";
// iterate through the words
foreach($words as $word) {
// chopword = the portion of the word that will be replaced
$chopword = $word;
$chopword = preg_replace('/^[^A-Za-z0-9]*/', '', $chopword);
if ($chopword <> '') {
// linkword = the text that will replace chopword in the word
$linkword='';
// does it start with http://abc. ?
if (preg_match('/^(http:\/\/)[a-zA-Z0-9_]{2,}.*/', $chopword)) {
$chopword = preg_replace('/[^A-Za-z0-9\/]*$/', '', $chopword);
$linkword = '<a href="'.$chopword.'" target="blank">'.$chopword.'</a>';
// does it equal abc.def.ghi ?
} else if (preg_match('/^[a-zA-Z]{2,}\.([a-zA-Z0-9_]+\.)+[a-zA-Z]{2,}(\/.*)?/', $chopword)) {
$chopword = preg_replace('/[^A-Za-z0-9\/]*$/', '', $chopword);
$linkword = '<a href="http://'.$chopword.'" target="blank">'.$chopword.'</a>';
// does it start with abc@def.ghi ?
} else if (preg_match('/^[a-zA-Z0-9_\.]+\@([a-zA-Z0-9_]{2,}\.)+[a-zA-Z]{2,}.*/', $chopword)) {
$chopword = preg_replace('/[^A-Za-z0-9]*$/', '', $chopword);
$linkword = '<a href="mailto:'.$chopword.'">'.$chopword.'</a>';
}
// replace chopword with linkword in word (if linkword was set)
if ($linkword <> '') {
$word = str_replace($chopword, $linkword, $word);
}
}
// append the word
$text = $text.$word;
}
return $text;
}