PHP实现文章内容关键词加链接类
时间:2024年05月30日
/来源:网络
/编辑:佚名
实现文章内关键词自动加链接(用于内链SEO等),长词优先替换,替换过的不会二次替换,可设置替换数量(一个关键词允许出现N次)等。
直接上源码:HotWords.class.php:
<?php
/**
* @abstract 内容热词(<a >热词</a>除外)加超链功能类
* @param string $content 内容
* @param array $keyWords 二维数组,格式: array(
* array('热词1', 'URL1'),
* array('热词2', 'URL2'),
* ...
* array('热词n', 'URLn')
* );
* @param int $times 同一个热词在内容中前$times次都将被加上超链
* @author WKD
*
*/
class HotWords{
protected $_content;
protected $_keyWords;
protected $_times;
public function __construct($content, $keyWords, $times){
$this->setContent($content);
$this->setKeyWords($keyWords);
$this->setTimes($times);
}
/**
* @abstract 给热词加链接
* @access public
*/
public function addHotLink(){
/**
* 思路说明:
* 1、对关键词数组进行排序,长的关键词排到前面,这样就可以先替换长的关键词
* 2、提取出所有html标签,暂存到数组里(<a>****</a>整体提取)
* 3、根据html标签对内容进行分割,将分割的内容保存到一个数组里
* 4、将没有了html标签的内容数组,用一个“特殊字符(临时替换html标签的中间变量$tempReplaeHtmlTag)”拼接成一个字符串
* 5、先用加密的热词替换4中得到的字符串中的热词,再用热词本身替换加密的热词
* 6、根据“特殊字符(临时替换html标签的中间变量)”将5中得到的字符串换成数组
* 7、拼接6中得到的数组与2中得到的html标签数组,即可。
*/
$content = $this->getContent(); //得到文章内容
$kWordsArr = $this->keyWordSort($this->getKeyWords()); //对热词进行排序
$htmlTagArr = $this->getAllHtmlTag($content); //得到内容中的html标签
$noHtmlContentArr = $this->splitContentByTag($content); //根据html标签对内容进行分割
$tempReplaeHtmlTag = '{' . md5('lvdora-news') .'}'; //临时替换html标签的中间变量
$tempReplaceArr = array();
$tempReplaceArr[1] = array();
$tempReplaceArr[2] = array();
$tmepReplaceArr[3] = array();
$temContent = implode($tempReplaeHtmlTag, $noHtmlContentArr);
//热词与链接对应
foreach ($kWordsArr as $key => $kWords){
$tempReplaceArr[1][] = '/' . preg_quote($kWords[0]) . '/i';
if(strpos($kWords[1], 'http://') === FALSE){
$tempReplaceArr[2][] = '<a href="http://www.phpin.net' . $kWords[1] . '" class="hotwords" target="_blank">' . $kWords[0] . '</a>';
}else{
$tempReplaceArr[2][] = '<a href="' . $kWords[1] . '" class="hotwords" target="_blank">' . $kWords[0] . '</a>';
}
$tempReplaceArr[3][] = '{' . md5($kWords[0]) . '}';
}
//对没有html标签的内容进行关键字替换,为了防止像“AAA”与“AAAB”的冲突,先用md5后的替换,再用原词替换md5后的
$temContent = preg_replace($tempReplaceArr[1], $tempReplaceArr[3], $temContent, $this->getTimes());
$temContent = str_replace($tempReplaceArr[3], $tempReplaceArr[2], $temContent);
$noHtmlContentArr = explode($tempReplaeHtmlTag, $temContent);
$result = '';
foreach ($noHtmlContentArr as $key => $val){
$result .= $val . $htmlTagArr[$key];
}
return $result;
}
/**
* @abstract 根据html标签对内容进行分割,将分割的内容返回。
* @param string $content 要分割的内容
* @return array
*/
protected function splitContentByTag($content){
return preg_split('/<a[^>]*>.*?<\/a>|<\/?[a-zA-Z]+[^>]*>/', $content);
}
/**
* @abstract 等到$content中的所有html标签
* @param string $content 内容
* @return unknown|multitype:
*/
protected function getAllHtmlTag($content){
/**
* 这边的正则就是将<>包着的内容都提取出来,
* 凡是需要将<>号当成内容显示的,都应当用转义字符<>来替换,
* 对于一切<>包着的内容都可以认为是标签。
* 事实上浏览器也是这么干的,很多在线的文本编辑器也会自动转义这些字符。
*/
preg_match_all('/<a[^>]*>.*?<\/a>|<\/?[a-zA-Z]+[^>]*>/', $content, $match);
if (isset($match[0])) {
$htmlTagArray = $match[0];
return $htmlTagArray;
}
return array();
}
/**
* @abstract 对关键词进行排序,最长的排前面
* @param array $keyWordsArr 热词(二维数组)
* @return array $keyWordsArr
*/
protected function keyWordSort($keyWordsArr){
usort($keyWordsArr, function ($a, $b){
$al = strlen($a[0]);
$bl = strlen($b[0]);
if ($al == $bl)
return 0;
return ($al > $bl) ? -1 : 1;
});
return $keyWordsArr;
}
/**
* @abstract 设置内容
* @param string $content 内容
* @access protected
*/
protected function setContent($content){
$this->_content = $content;
}
/**
* @abstract 得到热词管理的内容
* @access protected
*/
protected function getContent(){
return $this->_content;
}
/**
* @abstract 设置热词
* @param array $keyWords
* @access protected
*/
protected function setKeyWords($keyWords){
$this->_keyWords = $keyWords;
}
/**
* @abstract 得到热词
* @access protected
*/
protected function getKeyWords(){
return $this->_keyWords;
}
/**
* @abstract 设置热词替换次数
* @param int $times
* @access protected
*/
protected function setTimes($times){
$this->_times = $times > 0 ? $times : -1;
}
/**
* @abstract 得到替换次数
* @access protected
*/
protected function getTimes(){
return $this->_times;
}
}
测试例子代码:
<?php
define('APP_PATH', dirname(__FILE__));
require APP_PATH.'/HotWords.class.php';
header('Content-type:text/html; charset=utf-8');
//$time = microtime();
$content = file_get_contents('./test.txt');
$keywordArray = array(
array('进程', 'http://www.01happy.com/linux-ps-view-process/'),
array('守护进程', '/linux-python-daemon/'),
array('javascript','http://www.baidu.com/'),
array('java','http://s.jb51.net/'),
array('脚本之家','http://www.jb51.net/'),
);
$c = new HotWords($content, $keywordArray, 1);
$newContent = $c->addHotLink();
print $newContent;
//echo microtime() - $time;
?>
内容文本:
test.txt:
<p>python中如果要创建新<a href="#">进程</a>的话,可以使用os模块中的fork方法。为了了解其中工作原理,笔者结合linux的查看<a href="#">进程ps命令</a>,对这个方法做了一些测试。</p>
<p><strong class="last">python运行时进程</strong></p>
<p>python一开始运行的时候,系统会生成一个新的进程。先看下面代码:</p>
<pre>#!/usr/bin/env python
#coding=utf8
<iframe src="java/javascript.jpg"></iframe>
from time import sleep
sleep(30)</pre>
<p>因为代码执行完后,进程就会被销毁,所以这里睡眠30秒,方便看到效果。在linux下执行这个代码:</p>
<pre>python hello.py &</pre>
<p>加上&符号,可以让程序在后台运行,不会占用终端。输入ps -l命令查看进程,在电脑上输出如下:</p>
<div id="attachment_692" class="wp-caption aligncenter" style="width: 606px"><a href="http://www.01happy.com/wp-content/uploads/2012/11/python运行时进程.png"><img class="size-full wp-image-692 last" title="python运行时进程" src="http://www.01happy.com/wp-content/uploads/2012/11/python运行时进程.png" alt="python运行时进程" width="596" height="67"></a><p class="wp-caption-text last">python运行时进程</p></div>
<p>其中第二条记录就是刚才运行的python了。</p>
<p><strong class="last">使用fork来创建一个新进程</strong></p>
<p>使用fork创建一个新进程成功后,新进程会是原进程的子进程,原进程称为父进程。如果发生错误,则会抛出OSError异常。</p>
<pre>#!/usr/bin/env python
#coding=utf8
from time import sleep
import os
try:
pid = os.fork()
except OSError, e:
pass
sleep(30)</pre>
<p>运行代码,查看进程,在电脑上输出如下:</p>
<div id="attachment_693" class="wp-caption aligncenter" style="width: 599px"><a href="http://www.01happy.com/wp-content/uploads/2012/11/python中fork进程.png"><img class="size-full wp-image-693 last" title="python中fork进程" src="http://www.01happy.com/wp-content/uploads/2012/11/python中fork进程.png" alt="python中fork进程" width="589" height="83"></a><p class="wp-caption-text last">python中fork进程</p></div>
<p>可以看出第二条python进程就是第一条的子进程。</p>
<p><strong class="last">fork进程后的程序流程</strong></p>
<p>使用fork创建子进程后,子进程会复制父进程的数据信息,而后程序就分两个进程继续运行后面的程序,这也是fork(分叉)名字的含义了。在子进程内,这个方法会返回0;在父进程内,这个方法会返回子进程的编号PID。可以使用PID来区分两个进程:</p>
<pre>#!/usr/bin/env python
#coding=utf8
import os
#创建子进程之前声明的变量
source = 10
try:
pid = os.fork()
if pid == 0: #子进程
print "this is child process."
#在子进程中source自减1
source = source - 1
sleep(3)
else: #父进程
print "this is parent process."
print source
except OSError, e:
pass</pre>
<p>上面代码中,在子进程创建前,声明了一个变量source,然后在子进程中自减1,最后打印出source的值,显然父进程打印出来的值应该为10,子进程打印出来的值应该为9。为了明显区分父进程和子进程,让子进程睡3秒,就看的比较明显了。</p>
<p class="last">既然子进程是父进程创建的,那么父进程退出之后,子进程会怎么样呢?此时,子进程会被PID为1的进程接管,就是init进程了。这样子进程就不会受终端退出影响了,使用这个特性就可以创建在后台执行的程序,俗称守护进程(daemon)。</p>
<p>
在百度中搜索服务器软件就可以到脚本之家提供的软件<br />
夏季不再穿长筒袜近年成为一种时尚,甚至到了秋天也不例外。<br />
专家提出,<img src="java/javascript.jpg" alt='java' title='javascript' />其实这种时尚不利于美腿。据悉,久坐久站缺少运动等原因易导致静脉曲张,尤其是长期站立工作的人,容易引起下肢静脉本身扩张、延长或静脉瓣膜损坏以至发病。具体表现为腿部肿胀,下肢静脉犹如蚯蚓状弯曲或结节成团,皮肤发紫,特别是踝和小腿内侧更为严重。<br />
专家指出,长期站立工作的人或多或少都有一些下肢静脉曲张的表现,java不是javascript只是轻重程度不javascript一样。下肢静脉曲张是一种治疗起来比较麻烦的疾病,严重的需要手术,所以最好的方法还是防患于未然,在症状尚不明显的时候,就采取防范措施,穿长筒弹力袜就是一种很好的方法,可帮助血液进入较大且较深处的静脉。<br />
保持理想体重,可减少静脉曲张的机会;避免紧身衣物,穿医用弹力袜,以免使血液聚积在腿部;小心食用避孕药,某些避孕药可能引起这种问题。
<a href="java/javascript/java111.html" title="java">java</a>
</p>
直接上源码:HotWords.class.php:
<?php
/**
* @abstract 内容热词(<a >热词</a>除外)加超链功能类
* @param string $content 内容
* @param array $keyWords 二维数组,格式: array(
* array('热词1', 'URL1'),
* array('热词2', 'URL2'),
* ...
* array('热词n', 'URLn')
* );
* @param int $times 同一个热词在内容中前$times次都将被加上超链
* @author WKD
*
*/
class HotWords{
protected $_content;
protected $_keyWords;
protected $_times;
public function __construct($content, $keyWords, $times){
$this->setContent($content);
$this->setKeyWords($keyWords);
$this->setTimes($times);
}
/**
* @abstract 给热词加链接
* @access public
*/
public function addHotLink(){
/**
* 思路说明:
* 1、对关键词数组进行排序,长的关键词排到前面,这样就可以先替换长的关键词
* 2、提取出所有html标签,暂存到数组里(<a>****</a>整体提取)
* 3、根据html标签对内容进行分割,将分割的内容保存到一个数组里
* 4、将没有了html标签的内容数组,用一个“特殊字符(临时替换html标签的中间变量$tempReplaeHtmlTag)”拼接成一个字符串
* 5、先用加密的热词替换4中得到的字符串中的热词,再用热词本身替换加密的热词
* 6、根据“特殊字符(临时替换html标签的中间变量)”将5中得到的字符串换成数组
* 7、拼接6中得到的数组与2中得到的html标签数组,即可。
*/
$content = $this->getContent(); //得到文章内容
$kWordsArr = $this->keyWordSort($this->getKeyWords()); //对热词进行排序
$htmlTagArr = $this->getAllHtmlTag($content); //得到内容中的html标签
$noHtmlContentArr = $this->splitContentByTag($content); //根据html标签对内容进行分割
$tempReplaeHtmlTag = '{' . md5('lvdora-news') .'}'; //临时替换html标签的中间变量
$tempReplaceArr = array();
$tempReplaceArr[1] = array();
$tempReplaceArr[2] = array();
$tmepReplaceArr[3] = array();
$temContent = implode($tempReplaeHtmlTag, $noHtmlContentArr);
//热词与链接对应
foreach ($kWordsArr as $key => $kWords){
$tempReplaceArr[1][] = '/' . preg_quote($kWords[0]) . '/i';
if(strpos($kWords[1], 'http://') === FALSE){
$tempReplaceArr[2][] = '<a href="http://www.phpin.net' . $kWords[1] . '" class="hotwords" target="_blank">' . $kWords[0] . '</a>';
}else{
$tempReplaceArr[2][] = '<a href="' . $kWords[1] . '" class="hotwords" target="_blank">' . $kWords[0] . '</a>';
}
$tempReplaceArr[3][] = '{' . md5($kWords[0]) . '}';
}
//对没有html标签的内容进行关键字替换,为了防止像“AAA”与“AAAB”的冲突,先用md5后的替换,再用原词替换md5后的
$temContent = preg_replace($tempReplaceArr[1], $tempReplaceArr[3], $temContent, $this->getTimes());
$temContent = str_replace($tempReplaceArr[3], $tempReplaceArr[2], $temContent);
$noHtmlContentArr = explode($tempReplaeHtmlTag, $temContent);
$result = '';
foreach ($noHtmlContentArr as $key => $val){
$result .= $val . $htmlTagArr[$key];
}
return $result;
}
/**
* @abstract 根据html标签对内容进行分割,将分割的内容返回。
* @param string $content 要分割的内容
* @return array
*/
protected function splitContentByTag($content){
return preg_split('/<a[^>]*>.*?<\/a>|<\/?[a-zA-Z]+[^>]*>/', $content);
}
/**
* @abstract 等到$content中的所有html标签
* @param string $content 内容
* @return unknown|multitype:
*/
protected function getAllHtmlTag($content){
/**
* 这边的正则就是将<>包着的内容都提取出来,
* 凡是需要将<>号当成内容显示的,都应当用转义字符<>来替换,
* 对于一切<>包着的内容都可以认为是标签。
* 事实上浏览器也是这么干的,很多在线的文本编辑器也会自动转义这些字符。
*/
preg_match_all('/<a[^>]*>.*?<\/a>|<\/?[a-zA-Z]+[^>]*>/', $content, $match);
if (isset($match[0])) {
$htmlTagArray = $match[0];
return $htmlTagArray;
}
return array();
}
/**
* @abstract 对关键词进行排序,最长的排前面
* @param array $keyWordsArr 热词(二维数组)
* @return array $keyWordsArr
*/
protected function keyWordSort($keyWordsArr){
usort($keyWordsArr, function ($a, $b){
$al = strlen($a[0]);
$bl = strlen($b[0]);
if ($al == $bl)
return 0;
return ($al > $bl) ? -1 : 1;
});
return $keyWordsArr;
}
/**
* @abstract 设置内容
* @param string $content 内容
* @access protected
*/
protected function setContent($content){
$this->_content = $content;
}
/**
* @abstract 得到热词管理的内容
* @access protected
*/
protected function getContent(){
return $this->_content;
}
/**
* @abstract 设置热词
* @param array $keyWords
* @access protected
*/
protected function setKeyWords($keyWords){
$this->_keyWords = $keyWords;
}
/**
* @abstract 得到热词
* @access protected
*/
protected function getKeyWords(){
return $this->_keyWords;
}
/**
* @abstract 设置热词替换次数
* @param int $times
* @access protected
*/
protected function setTimes($times){
$this->_times = $times > 0 ? $times : -1;
}
/**
* @abstract 得到替换次数
* @access protected
*/
protected function getTimes(){
return $this->_times;
}
}
测试例子代码:
<?php
define('APP_PATH', dirname(__FILE__));
require APP_PATH.'/HotWords.class.php';
header('Content-type:text/html; charset=utf-8');
//$time = microtime();
$content = file_get_contents('./test.txt');
$keywordArray = array(
array('进程', 'http://www.01happy.com/linux-ps-view-process/'),
array('守护进程', '/linux-python-daemon/'),
array('javascript','http://www.baidu.com/'),
array('java','http://s.jb51.net/'),
array('脚本之家','http://www.jb51.net/'),
);
$c = new HotWords($content, $keywordArray, 1);
$newContent = $c->addHotLink();
print $newContent;
//echo microtime() - $time;
?>
内容文本:
test.txt:
<p>python中如果要创建新<a href="#">进程</a>的话,可以使用os模块中的fork方法。为了了解其中工作原理,笔者结合linux的查看<a href="#">进程ps命令</a>,对这个方法做了一些测试。</p>
<p><strong class="last">python运行时进程</strong></p>
<p>python一开始运行的时候,系统会生成一个新的进程。先看下面代码:</p>
<pre>#!/usr/bin/env python
#coding=utf8
<iframe src="java/javascript.jpg"></iframe>
from time import sleep
sleep(30)</pre>
<p>因为代码执行完后,进程就会被销毁,所以这里睡眠30秒,方便看到效果。在linux下执行这个代码:</p>
<pre>python hello.py &</pre>
<p>加上&符号,可以让程序在后台运行,不会占用终端。输入ps -l命令查看进程,在电脑上输出如下:</p>
<div id="attachment_692" class="wp-caption aligncenter" style="width: 606px"><a href="http://www.01happy.com/wp-content/uploads/2012/11/python运行时进程.png"><img class="size-full wp-image-692 last" title="python运行时进程" src="http://www.01happy.com/wp-content/uploads/2012/11/python运行时进程.png" alt="python运行时进程" width="596" height="67"></a><p class="wp-caption-text last">python运行时进程</p></div>
<p>其中第二条记录就是刚才运行的python了。</p>
<p><strong class="last">使用fork来创建一个新进程</strong></p>
<p>使用fork创建一个新进程成功后,新进程会是原进程的子进程,原进程称为父进程。如果发生错误,则会抛出OSError异常。</p>
<pre>#!/usr/bin/env python
#coding=utf8
from time import sleep
import os
try:
pid = os.fork()
except OSError, e:
pass
sleep(30)</pre>
<p>运行代码,查看进程,在电脑上输出如下:</p>
<div id="attachment_693" class="wp-caption aligncenter" style="width: 599px"><a href="http://www.01happy.com/wp-content/uploads/2012/11/python中fork进程.png"><img class="size-full wp-image-693 last" title="python中fork进程" src="http://www.01happy.com/wp-content/uploads/2012/11/python中fork进程.png" alt="python中fork进程" width="589" height="83"></a><p class="wp-caption-text last">python中fork进程</p></div>
<p>可以看出第二条python进程就是第一条的子进程。</p>
<p><strong class="last">fork进程后的程序流程</strong></p>
<p>使用fork创建子进程后,子进程会复制父进程的数据信息,而后程序就分两个进程继续运行后面的程序,这也是fork(分叉)名字的含义了。在子进程内,这个方法会返回0;在父进程内,这个方法会返回子进程的编号PID。可以使用PID来区分两个进程:</p>
<pre>#!/usr/bin/env python
#coding=utf8
import os
#创建子进程之前声明的变量
source = 10
try:
pid = os.fork()
if pid == 0: #子进程
print "this is child process."
#在子进程中source自减1
source = source - 1
sleep(3)
else: #父进程
print "this is parent process."
print source
except OSError, e:
pass</pre>
<p>上面代码中,在子进程创建前,声明了一个变量source,然后在子进程中自减1,最后打印出source的值,显然父进程打印出来的值应该为10,子进程打印出来的值应该为9。为了明显区分父进程和子进程,让子进程睡3秒,就看的比较明显了。</p>
<p class="last">既然子进程是父进程创建的,那么父进程退出之后,子进程会怎么样呢?此时,子进程会被PID为1的进程接管,就是init进程了。这样子进程就不会受终端退出影响了,使用这个特性就可以创建在后台执行的程序,俗称守护进程(daemon)。</p>
<p>
在百度中搜索服务器软件就可以到脚本之家提供的软件<br />
夏季不再穿长筒袜近年成为一种时尚,甚至到了秋天也不例外。<br />
专家提出,<img src="java/javascript.jpg" alt='java' title='javascript' />其实这种时尚不利于美腿。据悉,久坐久站缺少运动等原因易导致静脉曲张,尤其是长期站立工作的人,容易引起下肢静脉本身扩张、延长或静脉瓣膜损坏以至发病。具体表现为腿部肿胀,下肢静脉犹如蚯蚓状弯曲或结节成团,皮肤发紫,特别是踝和小腿内侧更为严重。<br />
专家指出,长期站立工作的人或多或少都有一些下肢静脉曲张的表现,java不是javascript只是轻重程度不javascript一样。下肢静脉曲张是一种治疗起来比较麻烦的疾病,严重的需要手术,所以最好的方法还是防患于未然,在症状尚不明显的时候,就采取防范措施,穿长筒弹力袜就是一种很好的方法,可帮助血液进入较大且较深处的静脉。<br />
保持理想体重,可减少静脉曲张的机会;避免紧身衣物,穿医用弹力袜,以免使血液聚积在腿部;小心食用避孕药,某些避孕药可能引起这种问题。
<a href="java/javascript/java111.html" title="java">java</a>
</p>
新闻资讯 更多
热门文章
- 178Moban源码谈谈免费源码与收费源码的区别
- 2帝国CMS忘记后台登陆用户名、密码、认证码的解决方法
- 3帝国CMS(EmpireCMS) v7.5后台任意代码执行漏洞及具体修复方法
- 4帝国CMS和WordPress 哪个好?哪个适合建站?
- 5如何解决Discuz的密码错误次数过多请15分钟后登陆的问题
- 6帝国cms灵动标签取得内容和栏目链接地址
- 7emlog pro 注册码“开心”教程(如果有一天,emlog官方版 或者 emlog免费版 跑路了,那用户怎么办?)
- 8帝国cms后台登录出现”您还未登录”怎么解决?
- 9织梦CMS在nginx下设置伪静态方法(附nginx伪静态规则)
- 10帝国cms7.5忘记登录密码 和忘记登录认证码以及多次登录 失败被锁定解决办法