497 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /*
 | |
|  * Plugin Name: Comment Center
 | |
|  * Version: 1.1.2
 | |
|  * Plugin URI: https://www.flatpress.org
 | |
|  * Author: FlatPress
 | |
|  * Author URI: https://www.flatpress.org
 | |
|  * Description: Manage your blog's comments: Set policies, publish or reject comments. Part of the standard distribution.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * This class interacts with Flaptress comment system.
 | |
|  */
 | |
| class plugin_commentcenter {
 | |
| 
 | |
| 	// The plugin configuration
 | |
| 	var $conf = array();
 | |
| 
 | |
| 	// The policies
 | |
| 	var $policies = array();
 | |
| 
 | |
| 	// The plugin_dir
 | |
| 	var $pl_dir = 'fp-content/plugin_commentcenter/';
 | |
| 
 | |
| 	/**
 | |
| 	 * This is the constructor.
 | |
| 	 */
 | |
| 	function __construct() {
 | |
| 		add_action('entry_block', array(
 | |
| 			&$this,
 | |
| 			'lock'
 | |
| 		));
 | |
| 		add_filter('comment_validate', array(
 | |
| 			&$this,
 | |
| 			'validate'
 | |
| 		), 5, 2);
 | |
| 		$this->pl_dir = FP_CONTENT . 'plugin_commentcenter/';
 | |
| 		if (!file_exists($this->pl_dir)) {
 | |
| 			fs_mkdir($this->pl_dir);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function loads the configuration of the plugin.
 | |
| 	 *
 | |
| 	 * @param boolean $foce:
 | |
| 	 *        	Force to load it?
 | |
| 	 * @return array: The configuration
 | |
| 	 */
 | |
| 	function getConf($force = false) {
 | |
| 		if (!empty($this->conf) && $force) {
 | |
| 			return $this->conf;
 | |
| 		}
 | |
| 		$this->conf = plugin_getoptions('commentcenter');
 | |
| 		return $this->conf;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function check if comment must be locked.
 | |
| 	 */
 | |
| 	function lock() {
 | |
| 		global $fp_params, $post, $smarty;
 | |
| 		$this->loadPolicies();
 | |
| 		$cats = array_key_exists('categories', $post) && is_array($post ['categories']) ? $post ['categories'] : array();
 | |
| 		$behavoir = array_key_exists('entry', $fp_params) ? $this->behavoirFromPolicies($fp_params ['entry'], $cats) : 1;
 | |
| 		if ($behavoir == -1 && !user_loggedin()) {
 | |
| 			$smarty->assign('entry_commslock', true);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function validates a comment.
 | |
| 	 *
 | |
| 	 * @param boolean $status:
 | |
| 	 *        	The current status of the comment validation
 | |
| 	 * @param array $comment:
 | |
| 	 *        	The comment data
 | |
| 	 * @return boolean: Is the comment valid?
 | |
| 	 */
 | |
| 	function validate($status, $comment) {
 | |
| 		global $smarty, $fp_params, $lang;
 | |
| 		// If the comment has been already stopped or this is the contact page, stop here our check
 | |
| 		if (!$status || function_exists('contact_display')) {
 | |
| 			return $status;
 | |
| 		}
 | |
| 
 | |
| 		// If the comment has been made from an administrator, don't check it
 | |
| 		if (@$comment ['loggedin']) {
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		$entry = $fp_params ['entry'];
 | |
| 		if (!isset($comment ['date'])) {
 | |
| 			$comment ['date'] = date_time();
 | |
| 		}
 | |
| 		$comment ['id'] = bdb_idfromtime(BDB_COMMENT, $comment ['date']);
 | |
| 		$conf = $this->getConf();
 | |
| 
 | |
| 		// This variables defines how the system has to behave.
 | |
| 		$behavoir = 1;
 | |
| 		$this->loadPolicies();
 | |
| 		// To get categories of the entry, we use the same method of PrettyURLs...
 | |
| 		global $post;
 | |
| 		$behavoir = $this->behavoirFromPolicies($entry, $post ['categories']);
 | |
| 
 | |
| 		// If comments are locked we don't send to Akismet
 | |
| 		if (@$conf ['akismet_check'] && $behavoir != -1) {
 | |
| 			$akismet = $this->akismetCheck($comment, $entry);
 | |
| 			if (!$akismet) {
 | |
| 				$smarty->append('error', $lang ['plugin'] ['commentcenter'] ['akismet_error']);
 | |
| 				$this->logComment($comment, $entry, 'akismet');
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if ($behavoir == 0) {
 | |
| 			$this->logComment($comment, $entry, 'confirm');
 | |
| 			$smarty->append('warnings', $lang ['plugin'] ['commentcenter'] ['approvation']);
 | |
| 			if (@$conf ['email_alert']) {
 | |
| 				$this->commentMail($comment, $post ['subject']);
 | |
| 			}
 | |
| 		} elseif ($behavoir == -1 && @$conf ['log_all']) {
 | |
| 			$this->logComment($comment, $entry, 'denided');
 | |
| 			$smarty->append('error', $lang ['plugin'] ['commentcenter'] ['lock']);
 | |
| 		}
 | |
| 
 | |
| 		if ($behavoir != 1) {
 | |
| 			// Delete the comment content
 | |
| 			$_POST ['content'] = '';
 | |
| 		}
 | |
| 
 | |
| 		// Also if the comment need to be approved, we return false.
 | |
| 		return $behavoir == 1;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function create an akismet instance.
 | |
| 	 * An Akismet object is returned by reference. But if an error
 | |
| 	 * happens, the function return a negative integer:
 | |
| 	 * -1 if we can't find the key
 | |
| 	 * -2 if we can't contact Akismet servers
 | |
| 	 * -3 if the response failed
 | |
| 	 * -4 if the key isn't valid
 | |
| 	 *
 | |
| 	 * @param string $key:
 | |
| 	 *        	A key for the service
 | |
| 	 * @return object: The akismet object
 | |
| 	 */
 | |
| 	function &akismetLoad($key = '') {
 | |
| 		$conf = $this->getConf();
 | |
| 
 | |
| 		if (!empty($key)) {
 | |
| 		} elseif (empty($conf ['akismet_key'])) {
 | |
| 			$e = -1;
 | |
| 			return $e;
 | |
| 		} else {
 | |
| 			$key = $conf ['akismet_key'];
 | |
| 		}
 | |
| 		$url = empty($conf ['akismet_url']) ? BLOG_BASEURL : $conf ['akismet_url'];
 | |
| 
 | |
| 		include_once dirname(__FILE__) . '/inc/akismet.class.php';
 | |
| 		$akismet = new Akismet($url, $key);
 | |
| 
 | |
| 		if ($akismet->errorsExist()) {
 | |
| 			$e = 0;
 | |
| 			switch (true) {
 | |
| 				case $akismet->isError(AKISMET_SERVER_NOT_FOUND):
 | |
| 					$e = -2;
 | |
| 					break;
 | |
| 				case $akismet->isError(AKISMET_RESPONSE_FAILED):
 | |
| 					$e = -3;
 | |
| 					break;
 | |
| 				case $akismet->isError(AKISMET_INVALID_KEY):
 | |
| 					$e = -4;
 | |
| 					break;
 | |
| 			}
 | |
| 			return $e;
 | |
| 		} else {
 | |
| 			return $akismet;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function clean a comment to send it to Akismet.
 | |
| 	 *
 | |
| 	 * @param array $comment:
 | |
| 	 *        	The comment data
 | |
| 	 * @param string $entry:
 | |
| 	 *        	The entry id
 | |
| 	 * @return array: $comment cleaned
 | |
| 	 */
 | |
| 	function akismetClean($comment, $entry) {
 | |
| 		global $post;
 | |
| 		$conf = $this->getConf();
 | |
| 
 | |
| 		$oldpost = $post;
 | |
| 		$o = new FPDB_Query("id:{$entry},fullparse:false", null);
 | |
| 		$arr = $o->getEntry();
 | |
| 		$post = $arr [1];
 | |
| 		$link = get_permalink($entry);
 | |
| 		if (!empty($conf ['akismet_url'])) {
 | |
| 			$link = $conf ['akismet_url'] . substr($link, strlen(BLOG_BASEURL));
 | |
| 		}
 | |
| 
 | |
| 		$post = $oldpost;
 | |
| 
 | |
| 		$clean = array(
 | |
| 			'author' => $comment ['name'],
 | |
| 			'email' => @$comment ['email'],
 | |
| 			'website' => @$comment ['url'],
 | |
| 			'body' => $comment ['content'],
 | |
| 			'user_ip' => @$comment ['ip-address'],
 | |
| 			'permalink' => $link
 | |
| 		);
 | |
| 
 | |
| 		return $clean;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function manages the Akismet Check
 | |
| 	 *
 | |
| 	 * @param array $comment:
 | |
| 	 *        	The comment data
 | |
| 	 * @param string $entry:
 | |
| 	 *        	The entry id
 | |
| 	 * @return boolean: Is the comment allowed?
 | |
| 	 */
 | |
| 	function akismetCheck($comment, $entry) {
 | |
| 		$akismet = &$this->akismetLoad();
 | |
| 		if (!is_object($akismet)) {
 | |
| 			// Failed to load it. We return true, but the comment isn't checked
 | |
| 			// TODO: Add an error logger? Or make different, configurable behaves?
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		$clean = $this->akismetClean($comment, $entry);
 | |
| 		$akismet->setComment($clean);
 | |
| 		if ($akismet->isSpam()) {
 | |
| 			// Akismet sign the comment as spam. Let's stop it.
 | |
| 			return false;
 | |
| 		} else {
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function loads the comment policies.
 | |
| 	 *
 | |
| 	 * @param boolean $force:
 | |
| 	 *        	Force to load them?
 | |
| 	 * @return array: The policies
 | |
| 	 */
 | |
| 	function &loadPolicies($force = false) {
 | |
| 		if (!$force && !empty($this->policies)) {
 | |
| 			return $this->policies;
 | |
| 		}
 | |
| 
 | |
| 		if (!file_exists($f = $this->pl_dir . 'policies.txt')) {
 | |
| 			$this->policies = array();
 | |
| 			return $this->policies;
 | |
| 		}
 | |
| 
 | |
| 		include $f;
 | |
| 		$this->policies = $policies;
 | |
| 		return $this->policies;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function saves the policies.
 | |
| 	 *
 | |
| 	 * @return boolean
 | |
| 	 */
 | |
| 	function savePolicies() {
 | |
| 		$this->policies = array_values($this->policies);
 | |
| 		return system_save($this->pl_dir . 'policies.txt', array(
 | |
| 			'policies' => $this->policies
 | |
| 		));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function adds a policy in a certain position.
 | |
| 	 *
 | |
| 	 * @param mixed $policy:
 | |
| 	 *        	The policy
 | |
| 	 * @param integer $position:
 | |
| 	 *        	The position
 | |
| 	 */
 | |
| 	function addPolicyAt($policy, $position) {
 | |
| 		if ($position < 0) {
 | |
| 			$position = count($this->policies) + $position + 1;
 | |
| 		}
 | |
| 		$before = array_slice($this->policies, 0, $position);
 | |
| 		$after = array_slice($this->policies, $position);
 | |
| 		$this->policies = array_merge($before, array(
 | |
| 			$policy
 | |
| 		), $after);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function moves a policy from a postition to another one.
 | |
| 	 *
 | |
| 	 * @param integer $old:
 | |
| 	 *        	The old position
 | |
| 	 * @param integer $new:
 | |
| 	 *        	The new position
 | |
| 	 */
 | |
| 	function policyMove($old, $new) {
 | |
| 		if (!isset($this->policies [$old])) {
 | |
| 			return false;
 | |
| 		}
 | |
| 		$new = $new > $old ? $new + 1 : $new;
 | |
| 		$del = $new > $old ? $old : $old + 1;
 | |
| 		$this->addPolicyAt($this->policies [$old], $new);
 | |
| 		if (isset($this->policies [$del])) {
 | |
| 			unset($this->policies [$del]);
 | |
| 		}
 | |
| 		$this->policies = array_values($this->policies);
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get behavoir from policies.
 | |
| 	 * 1: The user can comment
 | |
| 	 * 0: The comment need to be approved
 | |
| 	 * -1: The user can't comment
 | |
| 	 *
 | |
| 	 * @param string $entry:
 | |
| 	 *        	The entry id
 | |
| 	 * @param array $cats:
 | |
| 	 *        	The categories
 | |
| 	 * @return integer: The behavoir
 | |
| 	 */
 | |
| 	function behavoirFromPolicies($entry, $cats = array()) {
 | |
| 		if (!is_array($cats)) {
 | |
| 			$cats = array();
 | |
| 		}
 | |
| 		$date = date_from_id($entry);
 | |
| 		// check if $date is in expected format
 | |
| 		if (!array_key_exists('time', $date)) {
 | |
| 			return -1;
 | |
| 		}
 | |
| 		$time = $date ['time'];
 | |
| 		$return = 1;
 | |
| 		$pols = &$this->policies;
 | |
| 
 | |
| 		if (count($pols)) {
 | |
| 			foreach ($pols as $policy) {
 | |
| 				if (@$policy ['is_all']) {
 | |
| 					$return = $policy ['do'];
 | |
| 				} elseif (!empty($policy ['entry']) && is_array($policy ['entry'])) {
 | |
| 					if (in_array($entry, $policy ['entry'])) {
 | |
| 						$return = $policy ['do'];
 | |
| 					}
 | |
| 				} elseif (!empty($policy ['entry'])) {
 | |
| 					if ($entry == $policy ['entry']) {
 | |
| 						$return = $policy ['do'];
 | |
| 					}
 | |
| 				} else {
 | |
| 					$consider = true;
 | |
| 					if (!empty($policy ['categories'])) {
 | |
| 						$consider = count(array_intersect($policy ['categories'], $cats)) > 0;
 | |
| 					}
 | |
| 					if (!empty($policy ['older'])) {
 | |
| 						$consider = (time() - $time) > $policy ['older'];
 | |
| 					} else {
 | |
| 						if (!empty($policy ['time_less'])) {
 | |
| 							$consider = $time > $policy ['time_less'];
 | |
| 						}
 | |
| 						if (!empty($policy ['time_more'])) {
 | |
| 							$consider = $time < $policy ['time_more'];
 | |
| 						}
 | |
| 					}
 | |
| 					$return = $consider ? $policy ['do'] : $return;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $return;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function saves a comment into the plugin directory.
 | |
| 	 * Maybe it's considered SPAM by Akismet or the comment requires
 | |
| 	 * the Administrator's approvation.
 | |
| 	 *
 | |
| 	 * @param array $comment:
 | |
| 	 *        	The comment data
 | |
| 	 * @param string $entry:
 | |
| 	 *        	The entry id
 | |
| 	 * @param string $why:
 | |
| 	 *        	The reason of the log
 | |
| 	 * @return boolean: Can it saves the log?
 | |
| 	 */
 | |
| 	function logComment($comment, $entry, $why = '') {
 | |
| 		$f = $this->pl_dir . "e{$entry}_c{$comment['id']}.txt";
 | |
| 		if (!empty($why)) {
 | |
| 			$comment ['log_reason'] = $why;
 | |
| 		}
 | |
| 		return system_save($f, array(
 | |
| 			'comment' => $comment
 | |
| 		));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * This function send an email to the administrator with the comment data.
 | |
| 	 * It's based on the code of comment.php
 | |
| 	 *
 | |
| 	 * @param array $comment:
 | |
| 	 *        	The comment data
 | |
| 	 * @param string $entry_title:
 | |
| 	 *        	The title of the entry
 | |
| 	 * @return boolean
 | |
| 	 */
 | |
| 	function commentMail($comment, $entry_title) {
 | |
| 		global $lang, $fp_config;
 | |
| 
 | |
| 		$subject = $lang ['plugin'] ['commentcenter'] ['mail_subj'];
 | |
| 		$subject = sprintf($subject, $fp_config ['general'] ['title']);
 | |
| 
 | |
| 		$comm_mail = empty($comment ['email']) ? '' : "<{$comment['email']}>";
 | |
| 		$from_mail = $fp_config ['general'] ['email'];
 | |
| 
 | |
| 		$text = $lang ['plugin'] ['commentcenter'] ['mail_text'];
 | |
| 		$text = str_replace(array(
 | |
| 			'%toname%',
 | |
| 			'%fromname%',
 | |
| 			'%frommail%',
 | |
| 			'%entrytitle%',
 | |
| 			'%content%',
 | |
| 			'%blogtitle%'
 | |
| 		), array(
 | |
| 			$fp_config ['general'] ['author'],
 | |
| 			$comment ['name'],
 | |
| 			$comm_mail,
 | |
| 			$entry_title,
 | |
| 			$comment ['content'],
 | |
| 			$fp_config ['general'] ['title']
 | |
| 		), $text);
 | |
| 
 | |
| 		// for non-ASCII characters in the e-mail header use RFC 1342 — Encodes data with MIME base64
 | |
| 		return @utils_mail($from_mail, '=?utf-8?B?' . base64_encode($subject) . '?=', $text);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| $GLOBALS ['plugin_commentcenter'] = new plugin_commentcenter();
 | |
| 
 | |
| /**
 | |
|  * This class makes the list of comments that needs to be approved.
 | |
|  */
 | |
| class commentcenter_list extends fs_filelister {
 | |
| 
 | |
| 	/**
 | |
| 	 * This is the constructor of the class.
 | |
| 	 *
 | |
| 	 * @params string $dir: The directory to list
 | |
| 	 */
 | |
| 	function __construct($dir) {
 | |
| 		parent::__construct($dir);
 | |
| 	}
 | |
| 
 | |
| 	function _checkFile($directory, $file) {
 | |
| 		if (fnmatch('eentry*.txt', $file)) {
 | |
| 			$entry = substr($file, 1, 18);
 | |
| 			$comment = substr($file, 21, 20);
 | |
| 			$this->_list [$entry] [] = $comment;
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	function toDetails($entry = null) {
 | |
| 		$list = array();
 | |
| 		if (!is_null($entry) && @is_array($this->_list [$entry])) {
 | |
| 			foreach ($this->_list [$entry] as $commentid) {
 | |
| 				include $this->_directory . "/e{$entry}_c{$commentid}.txt";
 | |
| 				if (empty($comment ['log_reason'])) {
 | |
| 					$comment ['log_reason'] = 'nd';
 | |
| 				}
 | |
| 				$list [$comment ['log_reason']] [$commentid] = $comment;
 | |
| 			}
 | |
| 		} else {
 | |
| 			foreach ($this->_list as $key => $comments) {
 | |
| 				$list [$key] = $this->toDetails($key);
 | |
| 			}
 | |
| 		}
 | |
| 		return $list;
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| // If we're in administration area, we load admin panel
 | |
| if (defined('MOD_ADMIN_PANEL')) {
 | |
| 	include dirname(__FILE__) . '/inc/admin.php';
 | |
| 	include dirname(__FILE__) . '/inc/jslang.php';
 | |
| 	include dirname(__FILE__) . '/inc/editor.php';
 | |
| } | 
