只需要在 function.php 中添加以下代码即可,同时自动添加 target=”_blank”,如果链接中已有这两个属性,则不会重复添加。
我的这个版本不同于之前网上流传的那个版本,那个版本不知道是哪个菜鸟写的,虽然能实现功能,但那时间复杂度简直不能忍。。。
源代码带注释:
// 站外链接nofollow,target add_filter( 'the_content' , 'nofollow_a_links' ); function nofollow_a_links ( $content ) { $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>" ; if (preg_match_all( "/$regexp/siU" , $content , $matches , PREG_SET_ORDER)) { $srcUrl = $_SERVER [ 'SERVER_NAME' ]; $now_pos =0; for ( $i = 0; $i < count ( $matches ); $i ++) { //不包含本站域名,同时不是href="/dm/p/5" 这种形式 if ( strpos ( $matches [ $i ][0], $srcUrl ) === false && strpos ( $matches [ $i ][0], '//' ) !== false ) { $tag = $matches [ $i ][0]; $tag0 = $matches [ $i ][0]; $noFollow = '' ; //添加 _blank $pattern = '/target\s*=\s*"\s*_blank\s*"/' ; preg_match( $pattern , $tag2 , $match ); if ( count ( $match ) < 1) $noFollow .= ' target="_blank" ' ; //添加nofollow $pattern = '/rel\s*=\s*"\s*[n|d]ofollow\s*"/' ; preg_match( $pattern , $tag2 , $match ); if ( count ( $match ) < 1) $noFollow .= ' rel="nofollow" ' ; //写入 if ( $noFollow != '' ){ //只进行单次替换,且使用$now_pos 记录$content的处理进度 $now_pos = strpos ( $content , $tag0 , $now_pos ); $tag = rtrim( $tag , '>' ); $tag .= $noFollow . '>' ; $content = substr_replace( $content , $tag , $now_pos , strlen ( $tag0 ) ); } } } } return $content ; } |
经历
以前用的都是下面这段代码,网上随便找的,但是啥也没想,直接粘贴后就开始用了,效果也还行,就没有多研究这段代码了:
add_filter( 'the_content' , 'cn_nf_url_parse' ); function cn_nf_url_parse( $content ) { $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>" ; if (preg_match_all( "/$regexp/siU" , $content , $matches , PREG_SET_ORDER)) { if ( ! empty ( $matches ) ) { $srcUrl = get_option( 'siteurl' ); for ( $i =0; $i < count ( $matches ); $i ++) { $tag = $matches [ $i ][0]; $tag2 = $matches [ $i ][0]; $url = $matches [ $i ][0]; $noFollow = '' ; $pattern = '/target\s*=\s*"\s*_blank\s*"/' ; preg_match( $pattern , $tag2 , $match , PREG_OFFSET_CAPTURE); if ( count ( $match ) < 1 ) $noFollow .= ' target="_blank" ' ; $pattern = '/rel\s*=\s*"\s*[n|d]ofollow\s*"/' ; preg_match( $pattern , $tag2 , $match , PREG_OFFSET_CAPTURE); if ( count ( $match ) < 1 ) $noFollow .= ' rel="nofollow" ' ; $pos = strpos ( $url , $srcUrl ); if ( $pos === false) { $tag = rtrim ( $tag , '>' ); $tag .= $noFollow . '>' ; $content = str_replace ( $tag2 , $tag , $content ); } } } } $content = str_replace ( ']]>' , ']]>' , $content ); return $content ; } |
自动查找指向站外的链接,如果该链接指向站外,并且没有 nofollow 或 _blank,则会自动添加,功能上到还是都实现了,没啥问题。
然后是近日发现,对于 <a href=”/i/zytbz”> 这种链接,这段代码也会识别成站外链接。于是,我就准备把这段代码改改。
不看不要紧,一看才发现这段代码简直是坑爹啊!是发布专门用来拖慢我们的服务器的吗?
特别是最后这句,安的究竟是什么心:
$content = str_replace ( ']]>' , ']]>' , $content ); |
除此之外,这段代码的逻辑似乎就有一点问题:
1、对每个链接对象,先进行一个镜像,镜像中添加 nofollow 属性。
2、在判断这个链接是否指向站外,如果是,将 $content 当中的源链接用 str_replace 替换成修改后的链接。
这么想这两步都反了,应该先判断是否是站外链接,再添加属性才对。
其次,每一次 str_replace,都会将 $content 全部扫描一遍(从头到尾),然而最后只替换掉当中的一条,这太浪费时间了!(时间复杂度为 N+1)
最佳算法当然是对于 $content,查找到一条 A 链接,判断处理一条,时间复杂度为 1。
但我查阅了很多资料,PHP 中的所有查找函数都只能返回查找后的结果,而不能返回找到目标的位置,总之是没法实现了,后来换了实现方法,让复杂度降为 2,大家可以去看代码,不细说了。
只想说 PHP 还是不够灵活啊。
我的代码的优势
大大优化运行效率。
可以识别 <a href=”/dm/top10″> & <a href=”//baidu.com”>,这样的链接。
是否使用这段代码是有待商榷的,因为一个正常的网站是不会没有出站链接的。全部都被添加上了 nofollow 属性,反而很不正常。