plugins/comments/modules/yf_comments.class.php
<?php
/**
* Comments handler.
*
* @author YFix Team <yfix.dev@gmail.com>
* @version 1.0
*/
class yf_comments
{
/** @var int Number of comments to display on one page */
public $NUM_PER_PAGE = 20;
/** @var int Max post text length */
public $MAX_POST_TEXT_LENGTH = 10000;
/** @var bool Use bb codes or not */
public $USE_BB_CODES = true;
/** @var bool Use tree mode or not */
public $USE_TREE_MODE = false;
/** @var bool
Allow Authors to delete comments from other peoples
for their objects (profiles, galleries, blogs etc)
*/
public $ALLOW_DELETE_FOR_AUTHOR = true;
/** @var bool Use 'active' field */
public $PROCESS_STATUS_FIELD = true;
/** @var bool Auto filtering input text */
public $AUTO_FILTER_INPUT_TEXT = true;
/** @var bool Use is text checking */
public $JS_TEXT_CHECKING = true;
/** @var int Time min interval between 2 comments (in seconds). Set to 0 to disable */
public $ANTI_FLOOD_TIME = 60;
/** @var string @conf_skip */
public $_user_nick_field = 'nick';
/** @var string @conf_skip */
public $_add_allowed_method = '_comment_is_allowed';
/** @var string @conf_skip */
public $_edit_allowed_method = '_comment_edit_allowed';
/** @var string @conf_skip */
public $_delete_allowed_method = '_comment_delete_allowed';
/** @var string @conf_skip */
public $_view_email_allowed_method = '_comment_view_email_allowed';
/** @var string @conf_skip Trigger method (will be called on successful add/edit/delete) */
public $_on_update_trigger = '_comment_on_update';
/** @var int Edit limit time */
public $EDIT_LIMIT_TIME = 604800; // week
/** @var array Comment links @conf_skip */
public $COMMENT_LINKS = [
'news' => './?object=news&action=full_news&id=',
'articles' => './?object=articles&action=view&id=',
'blog' => './?object=blog&action=show_single_post&id=',
'gallery' => './?object=gallery&action=show_medium_size&id=',
];
/** @var int */
public $NUM_RSS = 10;
/** @var string @conf_skip */
public $HTML_LINK_REGEX = '/<a[^>]+href=([^ >]+)[^>]*>(.*?)<\/a>/si';
/** @var string @conf_skip */
public $BBCODE_LINK_REGEX = '/\[URL[^\]]*\](.+?)\[\/URL\]/si';
/** @var bool */
public $ANTI_SPAM_DETECT = false;
/** @var bool
When not register user write comment
*/
public $VIEW_EMAIL_FIELD = true;
/** @var bool */
public $CHECK_ALLOW_TO_VIEW_USER_EMAIL = false;
/**
* Framework constructor.
*/
public function _init()
{
}
/**
* Display comments block for given object name.
* @param mixed $params
*/
public function _show_for_object($params = [])
{
if ($this->USE_TREE_MODE) {
return $this->_show_for_object_tree($params);
}
$OBJECT_NAME = ! empty($params['object_name']) ? $params['object_name'] : $_GET['object'];
$OBJECT_ID = ! empty($params['object_id']) ? (int) ($params['object_id']) : (int) ($_GET['id']);
$STPL_NAME_MAIN = ! empty($params['stpl_main']) ? $params['stpl_main'] : 'comments/main';
$STPL_NAME_ITEM = ! empty($params['stpl_item']) ? $params['stpl_item'] : 'comments/item';
$PAGER_PATH = ! empty($params['pager_path']) ? $params['pager_path'] : '';
if (empty($OBJECT_NAME) || empty($OBJECT_ID)) {
return '';
}
$sql = 'SELECT * FROM ' . db('comments') . ' WHERE object_name="' . _es($OBJECT_NAME) . '" AND object_id=' . (int) $OBJECT_ID . ($this->PROCESS_STATUS_FIELD ? ' AND active=1 ' : '');
$order_sql = ' ORDER BY add_date DESC';
list($add_sql, $pages, $total) = common()->divide_pages(str_replace('SELECT *', 'SELECT id', $sql), $PAGER_PATH, null, $this->NUM_PER_PAGE);
$Q = db()->query($sql . $order_sql . $add_sql);
while ($A = db()->fetch_assoc($Q)) {
$comments_array[$A['id']] = $A;
if ($A['user_id']) {
$users_ids[$A['user_id']] = $A['user_id'];
}
}
// set comments read
if (main()->USER_ID && ! empty($comments_array)) {
module('unread')->_set_read('comments', array_keys($comments_array));
}
if ( ! empty($users_ids)) {
foreach ((array) user($users_ids, ['id', 'name', $this->_user_nick_field, 'photo_verified']) as $A) {
$users_names[$A['id']] = _display_name($A);
$GLOBALS['verified_photos'][$A['id']] = $A['photo_verified'];
}
}
module('reputation')->_get_reput_info_for_user_ids($users_ids);
// Try to find more complex checking methods
$obj = module($_GET['object']);
$edit_allowed_check_method = is_object($obj) && method_exists($obj, $this->_edit_allowed_method);
$delete_allowed_check_method = is_object($obj) && method_exists($obj, $this->_delete_allowed_method);
if ($this->CHECK_ALLOW_TO_VIEW_USER_EMAIL) {
$view_email_allowed_check_method = is_object($obj) && method_exists($obj, $this->_view_email_allowed_method);
}
if ($view_email_allowed_check_method) {
$m = $this->_view_email_allowed_method;
$view_email = (bool) module($_GET['object'])->$m(['object_id' => $OBJECT_ID]);
}
foreach ((array) $comments_array as $comment_info) {
if ($edit_allowed_check_method) {
$m = $this->_edit_allowed_method;
$edit_allowed = (bool) module($_GET['object'])->$m([
'user_id' => $comment_info['user_id'],
'object_id' => $comment_info['object_id'],
]);
} else {
$edit_allowed = main()->USER_ID && $comment_info['user_id'] == main()->USER_ID;
}
if ($delete_allowed_check_method) {
$m = $this->_delete_allowed_method;
$delete_allowed = (bool) module($_GET['object'])->$m([
'user_id' => $comment_info['user_id'],
'object_id' => $comment_info['object_id'],
]);
} else {
$delete_allowed = main()->USER_ID && $comment_info['user_id'] == main()->USER_ID;
}
if (MAIN_TYPE_ADMIN) {
$edit_allowed = true;
$delete_allowed = true;
}
$comment_info['text'] = str_replace(['\\\\', "\\'", '\\"'], ['\\', "'", '"'], $comment_info['text']);
if (($comment_info['text'] == '__comment was deleted__') && ($comment_info['user_id'] == '0')) {
$comment_info['text'] = t('comment was deleted');
}
$replace2 = [
'need_div' => (int) ($i > 0),
'bg_class' => ! (++$i % 2) ? 'bg1' : 'bg2',
'comment_id' => (int) ($comment_info['id']),
'user_name' => _prepare_html( ! empty($comment_info['user_id']) ? $users_names[$comment_info['user_id']] : $comment_info['user_name']),
'user_email' => $view_email ? _prepare_html($comment_info['user_email']) : '',
'user_avatar' => $comment_info['user_id'] ? _show_avatar($comment_info['user_id'], $users_names[$comment_info['user_id']], 1, 0) : '',
'user_profile_link' => $comment_info['user_id'] ? _profile_link($comment_info['user_id']) : '',
'user_email_link' => $comment_info['user_id'] ? _email_link($comment_info['user_id']) : '',
'add_date' => _format_date($comment_info['add_date'], 'long'),
'comment_text' => $this->_format_text($comment_info['text']),
'edit_comment_link' => $edit_allowed ? './?object=' . $_GET['object'] . '&action=edit_comment&id=' . $comment_info['id'] . _add_get(['page']) : '',
'delete_comment_link' => $delete_allowed ? './?object=' . $_GET['object'] . '&action=delete_comment&id=' . $comment_info['id'] . _add_get(['page']) : '',
'reput_text' => is_object($REPUT_OBJ) && isset($users_names[$comment_info['user_id']]) ? $REPUT_OBJ->_show_for_user($comment_info['user_id'], $users_reput_info[$comment_info['user_id']], false, ['comments', $comment_info['id']]) : '',
'user_id' => $comment_info['user_id'],
];
$items .= tpl()->parse($STPL_NAME_ITEM, $replace2);
}
if (main()->USER_ID) {
$add_comment_form = $this->_add($params);
} else {
$add_comment_form = '';
}
if ($params['allow_guests_posts']) {
$add_comment_form = $this->_add($params);
}
$replace = [
'comments' => $items,
'comments_pages' => $pages,
'num_comments' => (int) $total,
'add_comment_form' => $add_comment_form,
'login_link' => empty(main()->USER_ID) && MAIN_TYPE_USER ? './?object=login_form&go_url=' . $OBJECT_NAME . ';' . $_GET['action'] . ';id=' . $OBJECT_ID : '',
];
return tpl()->parse($STPL_NAME_MAIN, $replace);
}
/**
* Display comments tree.
* @param mixed $params
*/
public function _show_for_object_tree($params = [])
{
$OBJECT_NAME = ! empty($params['object_name']) ? $params['object_name'] : $_GET['object'];
$OBJECT_ID = ! empty($params['object_id']) ? (int) ($params['object_id']) : (int) ($_GET['id']);
$STPL_NAME_MAIN = ! empty($params['stpl_main']) ? $params['stpl_main'] : 'comments/main_tree';
$STPL_NAME_ITEM = ! empty($params['stpl_item']) ? $params['stpl_item'] : 'comments/item_tree';
$PAGER_PATH = ! empty($params['pager_path']) ? $params['pager_path'] : '';
$FORM_ACTION = ! empty($params['add_form_action']) ? $params['add_form_action'] : './?object=' . $_GET['object'] . '&action=add_comment&id=' . $OBJECT_ID;
$USE_TREE_MODE = ! empty($params['use_tree_mode']) ? $params['use_tree_mode'] : $this->USE_TREE_MODE;
if (empty($OBJECT_NAME) || empty($OBJECT_ID)) {
return '';
}
// Get current profile comments from db
$sql = 'SELECT * FROM ' . db('comments') . ' WHERE object_name="' . _es($OBJECT_NAME) . '" AND object_id=' . (int) $OBJECT_ID . ($this->PROCESS_STATUS_FIELD ? ' AND active=1 ' : '');
$order_sql = ' ORDER BY add_date ASC';
$Q = db()->query($sql . $order_sql);
while ($A = db()->fetch_assoc($Q)) {
$comments_array[$A['id']] = $A;
$comments_array_ids[$A['id']] = $A['parent_id'];
$users_ids[$A['user_id']] = $A['user_id'];
}
if (main()->USER_ID && ! empty($comments_array)) {
module('unread')->_set_read('comments', array_keys($comments_array));
}
// Try to get users names
if ( ! empty($users_ids)) {
foreach ((array) user($users_ids, ['id', 'name', $this->_user_nick_field, 'photo_verified']) as $A) {
$users_names[$A['id']] = _display_name($A);
$GLOBALS['verified_photos'][$A['id']] = $A['photo_verified'];
}
}
$users_reput_info = module('reputation')->_get_reput_info_for_user_ids($users_ids);
// Try to find more complex checking methods
$obj = module($_GET['object']);
$edit_allowed_check_method = is_object($obj) && method_exists($obj, $this->_edit_allowed_method);
$delete_allowed_check_method = is_object($obj) && method_exists($obj, $this->_delete_allowed_method);
if ($this->CHECK_ALLOW_TO_VIEW_USER_EMAIL) {
$view_email_allowed_check_method = is_object($obj) && method_exists($obj, $this->_view_email_allowed_method);
}
if ($view_email_allowed_check_method) {
$m = $this->_view_email_allowed_method;
$view_email = (bool) module($_GET['object'])->$m([
'object_id' => $OBJECT_ID,
]);
}
$this->_comment_array = $comments_array_ids;
$this->_comment_tree_array = [];
if ( ! empty($this->_comment_array)) {
foreach ((array) $this->_comment_array as $key => $value) {
if ($value == 0) {
$temp_array[$key] = $value;
}
}
$this->_sort_to_tree($temp_array);
}
foreach ((array) $this->_comment_tree_array as $comment_tree_info) {
$comment_info = $comments_array[$comment_tree_info['id']];
$level = $comment_tree_info['level'];
if ($edit_allowed_check_method) {
$m = $this->_edit_allowed_method;
$edit_allowed = (bool) module($_GET['object'])->$m([
'user_id' => $comment_info['user_id'],
'object_id' => $comment_info['object_id'],
]);
} else {
$edit_allowed = main()->USER_ID && $comment_info['user_id'] == main()->USER_ID;
}
if ($delete_allowed_check_method) {
$m = $this->_delete_allowed_method;
$delete_allowed = (bool) module($_GET['object'])->$m([
'user_id' => $comment_info['user_id'],
'object_id' => $comment_info['object_id'],
]);
} else {
$delete_allowed = main()->USER_ID && $comment_info['user_id'] == main()->USER_ID;
}
if (MAIN_TYPE_ADMIN) {
$edit_allowed = true;
$delete_allowed = true;
}
$comment_info['text'] = str_replace(['\\\\', "\\'", '\\"'], ['\\', "'", '"'], $comment_info['text']);
if (($comment_info['text'] == '__comment was deleted__') and ($comment_info['user_id'] == '0')) {
$comment_info['text'] = t(str_replace('__', '', $comment_info['text']));
}
$replace2 = [
'user_id' => (int) ($comment_info['user_id']),
'user_name' => _prepare_html( ! empty($comment_info['user_id']) ? $users_names[$comment_info['user_id']] : $comment_info['user_name']),
'user_email' => $view_email ? _prepare_html($comment_info['user_email']) : '',
'user_avatar' => $comment_info['user_id'] ? _show_avatar($comment_info['user_id'], $users_names[$comment_info['user_id']], 1, 0, 1) : '',
'user_profile_link' => $comment_info['user_id'] ? _profile_link($comment_info['user_id']) : '',
'user_email_link' => $comment_info['user_id'] ? _email_link($comment_info['user_id']) : '',
'add_date' => _format_date($comment_info['add_date'], 'long'),
'comment_text' => $this->_format_text($comment_info['text']),
'edit_comment_link' => $edit_allowed ? './?object=' . $_GET['object'] . '&action=edit_comment&id=' . $comment_info['id'] . _add_get(['page']) : '',
'delete_comment_link' => $delete_allowed ? './?object=' . $_GET['object'] . '&action=delete_comment&id=' . $comment_info['id'] . _add_get(['page']) : '',
'current_link' => './?object=' . $_GET['object'] . '&action=' . $_GET['action'] . '&id=' . $_GET['id'] . '#cid_' . $comment_info['id'],
'reput_text' => is_object($REPUT_OBJ) && isset($users_names[$comment_info['user_id']]) ? $REPUT_OBJ->_show_for_user($comment_info['user_id'], $users_reput_info[$comment_info['user_id']], false, ['comments', $comment_info['id']]) : '',
'id' => $comment_info['id'],
'comment_margin_left' => $level * 30,
];
$items .= tpl()->parse($STPL_NAME_ITEM, $replace2);
}
if ( ! empty(main()->USER_ID)) {
$add_comment_form = $this->_add($params);
} else {
$add_comment_form = '';
}
if ($params['allow_guests_posts']) {
$add_comment_form = $this->_add($params);
}
$replace = [
'comments' => $items,
'comments_pages' => $pages,
'num_comments' => (int) $total,
'add_comment_form' => $add_comment_form,
'login_link' => empty(main()->USER_ID) && MAIN_TYPE_USER ? './?object=login_form&go_url=' . $OBJECT_NAME . ';' . $_GET['action'] . ';id=' . $OBJECT_ID : '',
'add_comment_action' => $FORM_ACTION,
];
return tpl()->parse($STPL_NAME_MAIN, $replace);
}
/**
* Form to add comments.
* @param mixed $params
*/
public function _add($params = [])
{
return $this->_load_sub_module('comments_manage')->_add($params);
}
/**
* Do edit own comment.
* @param mixed $params
*/
public function _edit($params = [])
{
return $this->_load_sub_module('comments_manage')->_edit($params);
}
/**
* Do delete comment.
* @param mixed $params
*/
public function _delete($params = [])
{
return $this->_load_sub_module('comments_manage')->_delete($params);
}
/**
* Get number of comments for the given objects ids.
* @param mixed $params
*/
public function _get_num_comments($params = [])
{
$OBJECT_NAME = ! empty($params['object_name']) ? $params['object_name'] : $_GET['object'];
$OBJECTS_IDS = ! empty($params['objects_ids']) ? $params['objects_ids'] : '';
if (empty($OBJECTS_IDS)) {
return false;
}
$tmp_array = explode(',', $OBJECTS_IDS);
$OBJECTS_IDS = [];
foreach ((array) $tmp_array as $cur_id) {
if (empty($cur_id)) {
continue;
}
$OBJECTS_IDS[$cur_id] = $cur_id;
}
if (empty($OBJECTS_IDS)) {
return false;
}
return db()->get_2d(
'SELECT object_id, COUNT(id) AS num FROM ' . db('comments') . '
WHERE object_id IN(' . implode(',', $OBJECTS_IDS) . ') AND object_name="' . _es($OBJECT_NAME) . '"
GROUP BY object_id'
);
}
/**
* Format given text (convert BB Codes, new lines etc).
* @param mixed $body
*/
public function _format_text($body = '')
{
if (empty($body)) {
return '';
}
if ($this->USE_BB_CODES) {
$BB_CODES_OBJ = _class('bb_codes');
}
if ($this->USE_BB_CODES && is_object($BB_CODES_OBJ)) {
$body = $BB_CODES_OBJ->_process_text($body);
} else {
$body = nl2br(_prepare_html($body, 0));
}
return $body;
}
/**
* Comments tree sorting.
* @param mixed $comment
* @param mixed $level
*/
public function _sort_to_tree($comment, $level = 0)
{
if (empty($comment)) {
return false;
}
foreach ((array) $comment as $id => $parent_id) {
if (( ! in_array($id, $this->_comment_array)) and ( ! in_array($id, $this->_comment_tree_array))) {
$this->_comment_tree_array[] = ['id' => $id, 'level' => $level];
continue;
}
if (in_array($id, $this->_comment_array)) {
$this->_comment_tree_array[] = ['id' => $id, 'level' => $level];
$temp_array = [];
foreach ((array) $this->_comment_array as $key => $value) {
if ($value == $id) {
$temp_array[$key] = $value;
}
}
if ( ! empty($temp_array)) {
$this->_sort_to_tree($temp_array, $level + 1);
}
}
}
}
/**
* For user profile method.
* @param mixed $user_id
* @param mixed $MAX_SHOW_COMMENTS
*/
public function _for_user_profile($user_id, $MAX_SHOW_COMMENTS)
{
return $this->_load_sub_module('comments_integration')->_for_user_profile($user_id, $MAX_SHOW_COMMENTS);
}
/**
* For home page method.
* @param mixed $NUM_NEWEST_COMMENTS
*/
public function _for_home_page($NUM_NEWEST_COMMENTS = 4)
{
return $this->_load_sub_module('comments_integration')->_for_home_page($NUM_NEWEST_COMMENTS);
}
/**
* Hook for the RSS module.
*/
public function _rss_general()
{
return $this->_load_sub_module('comments_integration')->_rss_general();
}
/**
* Try to load sub_module.
* @param mixed $module_name
*/
public function _load_sub_module($module_name = '')
{
return _class($module_name, 'modules/comments/');
}
public function _unread()
{
if (empty($this->_user_info['last_view'])) {
return;
}
$Q = db()->query('SELECT id FROM ' . db('comments') . ' WHERE user_id != ' . (int) (main()->USER_ID) . ' AND add_date > ' . $this->_user_info['last_view']);
while ($A = db()->fetch_assoc($Q)) {
$ids[$A['id']] = $A['id'];
}
$link = process_url('./?object=comments&action=view_unread');
$unread = [
'count' => count((array) $ids),
'ids' => $ids,
'link' => $link,
];
return $unread;
}
public function view_unread()
{
if (empty(main()->USER_ID)) {
return;
}
$OBJ = module('unread');
if (is_object($OBJ)) {
$ids = $OBJ->_get_unread('comments');
}
$BB_CODES_OBJ = _class('bb_codes');
if ( ! empty($ids)) {
$sql = 'SELECT text,object_name,id,object_id FROM ' . db('comments') . ' WHERE id IN(' . implode(',', (array) $ids) . ')';
$order_sql = ' ORDER BY add_date DESC';
list($add_sql, $pages, $total) = common()->divide_pages($sql);
$Q = db()->query($sql . $order_sql . $add_sql);
while ($A = db()->fetch_assoc($Q)) {
$A['text'] = _truncate($A['text'], 50, true);
$A['text'] = $BB_CODES_OBJ->_force_close_bb_codes($A['text']);
$A['text'] = $this->_format_text($A['text']) . ' ...';
$OBJ = module($A['object_name']);
if (is_object($OBJ)) {
$action = $OBJ->_comments_params['return_action'];
$A['action'] = $action;
}
$comments_info[$A['id']] = $A;
}
}
$replace = [
'items' => $comments_info,
'pages' => $pages,
];
return tpl()->parse($_GET['object'] . '/unread', $replace);
}
}