<?php !defined('P_W') && exit('Forbidden');
/**
 * @desc 敏感詞掃描類
 *
 */
class PW_WordScan {
	/**
	 * @desc DB類
	 *
	 * @var object
	 */
	var $db;
	
	/**
	 * @desc 敏感詞過濾類
	 *
	 * @var object
	 */
	var $filter;
	
	/**
	 * @desc 跳詞數
	 *
	 * @var int
	 */
	var $skip = 0;
	
	/**
	 * @desc 是否開啟簡繁轉換: false=>否; true=>是
	 *
	 * @var BOOL
	 */
	var $convert = false;
	
	/**
	 * @desc 每次掃描記錄條數
	 *
	 * @var int
	 */
	var $pagesize;
	
	/**
	 * @desc 如何處理掃描結果:1=>帖子停止瀏覽; 0=>帖子正常瀏覽
	 *
	 * @var int
	 */
	var $dispose = 1;
	
	/**
	 * @desc 要掃描的指定版塊id
	 *
	 * @var int
	 */
	var $fid ;
	
	/**
	 * @desc 該版塊的記錄總數
	 *
	 * @var int
	 */
	var $count;
	
	/**
	 * @desc 該版塊已掃描的記錄數
	 *
	 * @var int
	 */
	var $progress;
	
	/**
	 * 該次掃描到的包含敏感詞的記錄數
	 *
	 * @var int
	 */
	var $result;
	
	/**
	 * @desc 該版塊下所有表進度
	 *
	 * @var int
	 */
	var $table_progress;
	
	/**
	 * @desc 當前掃描的數據表
	 *
	 * @var string
	 */
	var $table;
	
	/**
	 * @desc 最後一次掃描到的記錄id
	 *
	 * @var int
	 */
	var $objid;
	
	function PW_WordScan() {
		global $db,$db_wordsfb_setting;
		$this->db = $db;
		$this->filter = L::loadClass('FilterUtil', 'filter');
		
		if (empty($db_wordsfb_setting)) {
			$this->dispose = 0;
		}
	}
	
	/**
	 * @desc 掃描並返回結果
	 *
	 * @param int $fid -- 版塊ID
	 * @param int $result  -- 是否清空待審核記錄
	 * @param int $restart -- 是否重新掃描(清空掃描記錄)
	 * @param int $pagesize -- 每次掃描記錄條數
	 * @param int $skip -- 跳詞數
	 * @param int $convert -- 是否開啟簡繁轉換: 0=>否; 1=>是
	 * @return array -- 掃描進度:返回當前版塊的記錄總數和已掃描記錄數和提示id
	 * 
	 * prompt: 提示信息id
	 * 1 掃描完成
	 * 2 版塊無帖子
	 * 3 沒有新增的帖子
	 */
	function run($fid, $result = 0, $restart = 0, $pagesize = 1000, $skip = 0, $convert = false) {
		$this->fid = $fid;
		$this->skip = $skip;
		$this->convert = $convert;
		$this->pagesize = $pagesize;
		if ($restart == 1) {
			$this->ClearScanProgress();
		} else {
			$this->getProgress($result);
		}

		if (!$this->count) return array('prompt' => 2);
		
		if ($this->progress >= $this->count) return array('prompt' => 3);

		foreach ($this->table_progress as $table => $progress) {
			if ($table == 'pw_threads') {
				$sql = "SELECT COUNT(*) FROM $table WHERE tid>".S::sqlEscape($progress)." AND fid =".S::sqlEscape($this->fid);
				$new = $this->db->get_value($sql);
				if ($new) {//if (10 < $new) {
					$this->table = $table;
					$this->scanThreads();
					
					# 更新掃描進度
					$this->updateProgress();
					return array('progress' => $this->progress, 'count' => $this->count);
				}
			} else {
				$sql = "SELECT COUNT(*) FROM $table WHERE pid>".S::sqlEscape($progress)." AND fid =".S::sqlEscape($this->fid);
				$new = $this->db->get_value($sql);
				if ($new) {//if (10 < $new) {
					$this->table = $table;
					$finish = $this->scanPosts();

					# 更新掃描進度
					$this->updateProgress();
					return array('progress' => $this->progress, 'count' => $this->count);
				}
			}
		}
		return array('progress' => $this->progress, 'count' => $this->count, 'prompt' => 1);
	}
	
	/**
	 * @desc 掃描主題表
	 */
	function scanThreads() {
		# 獲取主題信息,判斷是否重復記錄
		$sql = " SELECT t.tid, t.subject, t.ifcheck, t.postdate, t.author, f.id, f.state "
			 . " FROM $this->table AS t LEFT JOIN pw_filter AS f ON t.tid = f.tid"
			 . " WHERE t.tid>".S::sqlEscape($this->table_progress[$this->table])." AND t.fid =".S::sqlEscape($this->fid)
			 . " GROUP BY t.tid ORDER BY t.tid ASC LIMIT ".$this->pagesize;
		$query = $this->db->query($sql);
		
		$num = 0;
		while ($thread = $this->db->fetch_array($query)) {
			# 獲取帖子內容
			$pw_tmsgs = GetTtable($thread['tid']);
			$sql = " SELECT content FROM $pw_tmsgs WHERE tid=".S::sqlEscape($thread['tid']);
			$thread['content'] = $this->db->get_value($sql);
			
			# 掃描進度
			$this->progress++;
			$this->objid = $thread['tid'];
						
			# 帖子內容
			$content = $thread['subject'] . $thread['content'];
	
			# 過濾敏感詞
			$result = $this->filter->paraseContent($content, $this->skip, $this->convert);
	
			# 處理掃描結果
			if (is_array($result)) {
				$word  = $this->getWordString($result[1]);	
				$score = round($result[0], 2);
		
				if ($this->dispose && $score > 0 && $thread['ifcheck']) {
					# 更改審核狀態
					//$sql = "UPDATE pw_threads SET ifcheck=0 WHERE tid = " .S::sqlEscape($thread['tid']);
					pwQuery::update('pw_threads', 'tid=:tid', array($thread['tid']), array('ifcheck'=>0));
					
					$num++;
							
					# 更新版塊信息
					$this->updateCache();
						
					# 發消息通知
					$msg = array(
						'subject' => $thread['subject'],
						'tid' 	  => $thread['tid'],
						'fid' 	  => $this->fid,
					);
					$this->sendMsg($thread['author'], $msg, 't');
				}

				if (!$thread['id']) {
					# 如果不重復,掃描到的結果+1
					$this->result++;
					
					$compart = $insertString ? ',' : '';
					# 處理數據
					$insertString .= $compart . "( " . S::sqlEscape($thread['tid']) . ", " . S::sqlEscape($word) . ", "
							      . S::sqlEscape($thread['postdate']) . ")";					
				} elseif ($thread['state']) {
					# 如果是已經審核通過的再次被掃到,掃描到的結果+1
					$this->result++;
		
					# 處理數據
					$value = array(
						'state'  => 0,
						'filter' => $word,
						'created_at' => $thread['postdate'],
					);
					$value = S::sqlSingle($value);
		
					# 更新記錄
					$sql = "UPDATE pw_filter SET {$value} WHERE pid=0 AND tid = " . S::sqlEscape($thread['tid']);
					$this->db->update($sql);
				}
			}
		}
		
		# 插入記錄
		if ($insertString) {
			$insertSql =  "INSERT INTO pw_filter (tid, filter, created_at) VALUES " . $insertString;
			$this->db->update($insertSql);
		}
		
		if ($this->dispose && $num) {
			$this->updateCache($num);
		}
	}
	
	/**
	 * @desc 更新因帖子狀態改變而影響的版塊信息
	 */
	function updateCache($num) {
		/**
		$sql = "UPDATE pw_forumdata SET article=article-".S::sqlEscape($num,false).",topic=topic-".S::sqlEscape($num,false)." WHERE fid=".S::sqlEscape($this->fid);
		$this->db->update($sql);
		**/
		$this->db->update(pwQuery::buildClause("UPDATE :pw_table SET article=article-:article,topic=topic-:topic WHERE fid=:fid", array('pw_forumdata', $num, $num, $this->fid)));
	}
	
	/**
	 * @desc 掃描回復表
	 */
	function scanPosts()
	{
		# 獲取帖子信息,判斷是否重復記錄
		$sql = "SELECT p.pid,p.content,p.subject,t.tid,t.subject AS title,p.author,p.postdate,p.ifcheck,f.id,f.state "
			 . "FROM $this->table AS p LEFT JOIN pw_threads AS t ON p.tid=t.tid LEFT JOIN pw_filter AS f ON p.pid = f.pid "
			 . "WHERE p.tid > 0 AND p.pid>".S::sqlEscape($this->table_progress[$this->table])
			 ." AND t.fid =".S::sqlEscape($this->fid)
			 . " GROUP BY p.pid ORDER BY p.pid ASC LIMIT ".$this->pagesize;
		$query = $this->db->query($sql);		
		while ($post = $this->db->fetch_array($query)) {
			
			# 掃描進度
			$this->progress++;
			$this->objid = $post['pid'];
		
			# 內容
			$content = $post['subject'] . $post['content'];
			# 過濾敏感詞
			$result = $this->filter->paraseContent($content, $this->skip, $this->convert);
		
			# 處理掃描結果
			if(is_array($result)) {		
				$word  = $this->getWordString($result[1]);	
				$score = round($result[0], 2);
		
				if ($this->dispose && $score > 0 && $post['ifcheck']) {
					$tids[$post['tid']]++;
					# 待審核
					$sql = "UPDATE $this->table SET ifcheck=0 WHERE pid = " .S::sqlEscape($post['pid']);
					$this->db->update($sql);
						
					# 發消息通知
					$msg = array(
						'subject' => $post['title'],
						'tid' => $post['tid'],
						'pid' => $post['pid'],
						'fid' => $this->fid,
					);
					$this->sendMsg($post['author'], $msg, 'p');
				}
		
				if (!$post['id']) {
					# 如果不是重復記錄,掃描到的結果+1
					$this->result++;
		
					$compart = $insertSql ? ',' : '';
					# 處理數據
					$insertSql .= $compart . "( " . S::sqlEscape($post['tid']) . ", " . S::sqlEscape($post['pid']) 
									  . ", " . S::sqlEscape($word) . ", " . S::sqlEscape($post['postdate']) . ")";
				} elseif ($post['state']) {					
					# 如果是已經處理過的審核記錄再次被掃到,掃描到的結果+1
					$this->result++;
							
					# 處理數據
					$value = array(
						'state'  => 0,
						'filter' => $word,
						'created_at' => $post['postdate'],
					);
					$value = S::sqlSingle($value);
		
					# 更新記錄
					$sql = "UPDATE pw_filter SET {$value} WHERE tid=".S::sqlEscape($post['tid'])." AND pid=" . S::sqlEscape($post['pid']);
					$this->db->update($sql);
				}
			}			
		}

		if ($this->dispose && $tids) {
			# 總文章數
			$article = 0;
				
			foreach ($tids as $key => $value) {				
				# 更新主題帖回復數
				//$sql = "UPDATE pw_threads SET replies=replies-".S::sqlEscape($value,false)." WHERE tid=".S::sqlEscape($key);
				$sql = pwQuery::buildClause('UPDATE :pw_table SET replies=replies-:replies WHERE tid=:tid', array('pw_threads', $value, $key));
				$this->db->update($sql);
				
				$article += $value;
			}
			
			# 更新版塊文章數
			/**
			$sql = "UPDATE pw_forumdata SET article=article-".S::sqlEscape($article,false)." WHERE fid=".S::sqlEscape($this->fid);
			$this->db->update($sql);
			**/
			$this->db->update(pwQuery::buildClause("UPDATE :pw_table SET article=article-:article WHERE fid=:fid", array('pw_forumdata', $article, $this->fid)));
		}
		
		# 插入記錄
		if ($insertSql) {
			$sql =  "INSERT INTO pw_filter (tid, pid, filter, created_at) VALUES " . $insertSql;
			$this->db->update($sql);
		}
	}
	
	/**
	 * @desc 發消息通知用戶帖子被封
	 *
	 * @param string $user -- 收件人用戶名
	 * @param array $L     -- 消息內容信息
	 * @param string $type -- 帖子類型:t=>主題;p=>回復
	 */
	function sendMsg($user, $L, $type = 't') {
		if ($type == 't') {		
			$title	 = getLangInfo('cpmsg','filtermsg_thread_title');
			$content = getLangInfo('cpmsg','filtermsg_thread_content', $L);
		} else {
			$title	 = getLangInfo('cpmsg','filtermsg_post_title');
			$content = getLangInfo('cpmsg','filtermsg_post_content', $L);
		}
	
		M::sendNotice(
			array($user),
			array(
				'title' => $title,
				'content' => $content,
			)
		);
	}
	
	/**
	 * @desc 清空掃描進度
	 */
	function ClearScanProgress() {
		global $db_plist;
		
		# 讀取緩存
		//* require_once pwCache::getPath(D_P.'data/bbscache/wordsfb_progress.php');
		extract(pwCache::getData(D_P.'data/bbscache/wordsfb_progress.php', false));
		$this->threaddb = unserialize($threaddb);
		$this->catedb   = unserialize($catedb);
		$temp_threaddb = unserialize($threaddb);
		
		# 獲取主題表
		$sql = "SELECT COUNT(*) AS count FROM pw_threads WHERE fid =".S::sqlEscape($this->fid);
		$count = $this->db->get_value($sql);
		
		# 獲取回復表
		if ($db_plist && is_array($db_plist)) {
			foreach ($db_plist as $key=>$value) {
				if ($key>0) {
					$postslist[] = 'pw_posts'.(int)$key;
				} else {
					$postslist[] = 'pw_posts';
				}
			}
		} else {
			$postslist[] = 'pw_posts';
		}
			
		foreach ($postslist as $pw_posts) {
			$sql = "SELECT COUNT(*) AS count FROM $pw_posts WHERE fid =".S::sqlEscape($this->fid);
			$postcount = $this->db->get_value($sql);
			$count += $postcount;
		}
		
		foreach ($temp_threaddb as $key => $forums) {
			foreach ($forums  as $key2 => $value) {
				if ($this->fid == $key2) {
					
					foreach ($value['table_progress'] as $table => $progress) {
						$value['table_progress'][$table] = 0;
					}
					
					$this->count = $count;
					$this->progress = 0;
					$this->result = 0;
					$this->table_progress = $value['table_progress'];
					
					$temp_threaddb[$key][$key2]['count'] = $this->count;
					$temp_threaddb[$key][$key2]['progress'] = $this->progress;
					$temp_threaddb[$key][$key2]['result'] = $this->result;
					$temp_threaddb[$key][$key2]['table_progress'] = $this->table_progress;
				}
			}
		}
		$this->threaddb = $temp_threaddb;
		$threaddb = serialize($temp_threaddb);
	
		# 寫入文件	
		$filecontent = "<?php\r\n";
		$filecontent.="\$catedb=".pw_var_export($catedb).";\r\n";
		$filecontent.="\$threaddb=".pw_var_export($threaddb).";\r\n";
		$filecontent.="?>";
		$cahce_file = D_P.'data/bbscache/wordsfb_progress.php';
		pwCache::setData($cahce_file, $filecontent);
	}
	
	/**
	 * @desc 獲取掃描進度
	 */
	function getProgress($result)
	{
		global $db_plist;
		
		# 讀取緩存
		//* require_once pwCache::getPath(D_P.'data/bbscache/wordsfb_progress.php');
		extract(pwCache::getData(D_P.'data/bbscache/wordsfb_progress.php', false));
		$this->threaddb = unserialize($threaddb);
		$this->catedb   = unserialize($catedb);
		$temp_threaddb = unserialize($threaddb);
		
		# 獲取主題帖總數
		$sql = "SELECT COUNT(*) AS count FROM pw_threads WHERE fid =".S::sqlEscape($this->fid);
		$count = $this->db->get_value($sql);
		
		# 獲取回復表
		if ($db_plist && is_array($db_plist)) {
			foreach ($db_plist as $key=>$value) {
				if ($key>0) {
					$postslist[] = 'pw_posts'.(int)$key;
				} else {
					$postslist[] = 'pw_posts';
				}
			}
		} else {
			$postslist[] = 'pw_posts';
		}
		
		# 獲取回復帖數量
		foreach ($postslist as $pw_posts) {
			$sql = "SELECT COUNT(*) AS count FROM $pw_posts WHERE fid =".S::sqlEscape($this->fid);
			$postcount = $this->db->get_value($sql);
			$count += $postcount;
		}

		foreach ($temp_threaddb as $key => $forums) {
			foreach ($forums  as $key2 => $value) {
				if ($this->fid == $key2) {
					$this->table_progress = $value['table_progress'];
					$this->count = $count;
					$this->progress = $value['progress'];
					if ($result == 1) {
						$this->result = 0;
					} else {
						$this->result = $value['result'];
					}
					
					$temp_threaddb[$key][$key2]['count'] = $this->count;
					$temp_threaddb[$key][$key2]['progress'] = $this->progress;
					$temp_threaddb[$key][$key2]['result'] = $this->result;
					$temp_threaddb[$key][$key2]['table_progress'] = $this->table_progress;
				}
			}
		}

		$this->threaddb = $temp_threaddb;
		$threaddb = serialize($temp_threaddb);
		$catedb   = serialize($this->catedb);
	
		# 寫入文件	
		$filecontent = "<?php\r\n";
		$filecontent.="\$catedb=".pw_var_export($catedb).";\r\n";
		$filecontent.="\$threaddb=".pw_var_export($threaddb).";\r\n";
		$filecontent.="?>";
		$cahce_file = D_P.'data/bbscache/wordsfb_progress.php';
		pwCache::setData($cahce_file, $filecontent);
	}
	
	/*function getProgress()
	{
		# 讀取緩存
		require_once(D_P.'data/bbscache/wordsfb_progress.php');
		$this->threaddb = unserialize($threaddb);
		$this->catedb   = unserialize($catedb);
				
		foreach ($this->threaddb as $key => $forums) {
			foreach ($forums  as $key2 => $value) {
				if ($this->fid == $key2) {
					$this->table_progress = $value['table_progress'];
					$this->count = $value['count'];
					$this->progress = $value['progress'];
					$this->result = $value['result'];
				}
			}
		}
	}*/
	
	/**
	 * @desc 更新掃描進度
	 */
	function updateProgress() {
		if ($this->progress > $this->count) $this->progress = $this->count;
		if ($this->objid) {
			foreach ($this->threaddb as $key => $forums) {
				foreach ($forums  as $key2 => $value) {
					if ($this->fid == $key2) {
						$this->threaddb[$key][$key2]['progress'] = $this->progress;
						$this->threaddb[$key][$key2]['result']   = $this->result;
						$this->threaddb[$key][$key2]['table_progress'][$this->table] = $this->objid;
					}
				}
			}
			$threaddb = serialize($this->threaddb);
			$catedb = serialize($this->catedb);
		
			# 寫入文件	
			$filecontent = "<?php\r\n";
			$filecontent.="\$catedb=".pw_var_export($catedb).";\r\n";
			$filecontent.="\$threaddb=".pw_var_export($threaddb).";\r\n";
			$filecontent.="?>";
			$cahce_file = D_P.'data/bbscache/wordsfb_progress.php';
			pwCache::setData($cahce_file, $filecontent);
		}
	}
	
	/**
	 * @desc 將掃描出的敏感詞數組過濾成字符串
	 *
	 * @param unknown_type $strArray
	 * @return unknown
	 */
	function getWordString($strArray) {
		$array = array();
		
		foreach ($strArray as $value) {
			$array[] = $value[0];
		}
	
		$array = array_unique($array);
	
		$string='';
		foreach($array as $key=>$val) {
			if ($val) {
				$string .= $string ? ','.$val : $val;
			}
		}
		
		return $string;
	}
}