= 0)) { date_default_timezone_set('UTC'); } Table::addIncludePath(JPATH_ROOT . '/administrator/components/com_jcomments/tables'); /** * Frontend event handler * * @since 3.0 */ class JCommentsAJAX { public static function prepareValues(&$values) { foreach ($values as $k => $v) { if ($k == 'comment') { // Strip all HTML except [code] $m = array(); preg_match_all('#(\[code\=?([a-z0-9]*?)\].*\[\/code\])#isUu', trim($v), $m); $tmp = array(); $key = ''; foreach ($m[1] as $code) { $key = '{' . md5($code . $key) . '}'; $tmp[$key] = $code; $v = preg_replace('#' . preg_quote($code, '#') . '#isUu', $key, $v); } $v = trim(strip_tags($v)); $v = JCommentsText::nl2br($v); foreach ($tmp as $key => $code) { $v = preg_replace('#' . preg_quote($key, '#') . '#isUu', $code, $v); } unset($tmp, $m); $values[$k] = $v; } else { $values[$k] = trim(strip_tags($v)); } } return $values; } public static function escapeMessage($message) { $message = str_replace("\n", '\n', $message); $message = str_replace('\n', '
', $message); return JCommentsText::jsEscape($message); } public static function showErrorMessage($message, $name = '', $target = '') { $message = self::escapeMessage($message); $response = JCommentsFactory::getAjaxResponse(); $response->addScript("jcomments.error('$message','$target','$name');"); } public static function showInfoMessage($message, $target = '') { $message = self::escapeMessage($message); $response = JCommentsFactory::getAjaxResponse(); $response->addScript("jcomments.message('$message', '$target');"); } public static function showForm($objectID, $objectGroup, $target) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $response = JCommentsFactory::getAjaxResponse(); $objectGroup = JCommentsSecurity::clearObjectGroup($objectGroup); $form = JComments::getCommentsForm($objectID, $objectGroup); $response->addAssign($target, 'innerHTML', $form); return $response; } public static function showReportForm($id, $target) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $config = ComponentHelper::getParams('com_jcomments'); if ((int) $config->get('report_reason_required') == 0) { Factory::getApplication()->input->post->set('commentid', (int) $id); $response = JCommentsFactory::getAjaxResponse(); $response->addAssign($target, 'innerHTML', '
'); return self::reportComment(); } else { $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load($id)) { $form = JComments::getCommentsReportForm($id, $comment->object_id, $comment->object_group); $response->addAssign($target, 'innerHTML', $form); } return $response; } } public static function addComment($values = array()) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $app = Factory::getApplication(); /** @var User $user */ $user = $app->getIdentity(); $lang = $app->getLanguage(); $acl = JCommentsFactory::getACL(); $config = ComponentHelper::getParams('com_jcomments'); $response = JCommentsFactory::getAjaxResponse(); if ($user->authorise('comment.comment', 'com_jcomments')) { $values = self::prepareValues($_POST); $objectGroup = isset($values['object_group']) ? JCommentsSecurity::clearObjectGroup($values['object_group']) : ''; $objectID = isset($values['object_id']) ? (int) $values['object_id'] : ''; if ($objectGroup == '' || $objectID == '') { $response->addAlert(self::escapeMessage(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'))); return $response; } $commentsPerObject = (int) $config->get('max_comments_per_object'); if ($commentsPerObject > 0) { $commentsCount = JComments::getCommentsCount($objectID, $objectGroup); if ($commentsCount >= $commentsPerObject) { $message = $config->get('message_locked'); if (empty($message)) { $message = Text::_('ERROR_CANT_COMMENT'); } $response->addAlert(self::escapeMessage($message)); return $response; } } $userIP = $_SERVER['REMOTE_ADDR']; if (!$user->get('id')) { $noErrors = false; if (isset($values['userid']) && intval($values['userid']) > 0) { // TODO: we need more correct way to detect login timeout. Add session token check. self::showErrorMessage(Text::_('ERROR_SESSION_EXPIRED')); } elseif (($config->get('author_name', 2) == 2) && empty($values['name'])) { self::showErrorMessage(Text::_('ERROR_EMPTY_NAME'), 'name'); } elseif (JCommentsSecurity::checkIsRegisteredUsername($values['name']) == 1) { self::showErrorMessage(Text::_('ERROR_NAME_EXISTS'), 'name'); } elseif (JCommentsSecurity::checkIsForbiddenUsername($values['name']) == 1) { self::showErrorMessage(Text::_('ERROR_FORBIDDEN_NAME'), 'name'); } elseif (preg_match('/[\"\'\[\]\=\<\>\(\)\;]+/', $values['name'])) { self::showErrorMessage(Text::_('ERROR_INVALID_NAME'), 'name'); } elseif (($config->get('username_maxlength') != 0) && (StringHelper::strlen($values['name']) > $config->get('username_maxlength'))) { self::showErrorMessage(Text::_('ERROR_TOO_LONG_USERNAME'), 'name'); } elseif (((int) $config->get('author_email') == 2) && empty($values['email'])) { self::showErrorMessage(Text::_('ERROR_EMPTY_EMAIL'), 'email'); } elseif (!empty($values['email']) && (!preg_match(_JC_REGEXP_EMAIL2, $values['email']))) { self::showErrorMessage(Text::_('ERROR_INCORRECT_EMAIL'), 'email'); } elseif (((int) $config->get('author_email') != 0) && JCommentsSecurity::checkIsRegisteredEmail($values['email']) == 1) { self::showErrorMessage(Text::_('ERROR_EMAIL_EXISTS'), 'email'); } elseif (((int) $config->get('author_homepage') == 2) && empty($values['homepage'])) { self::showErrorMessage(Text::_('ERROR_EMPTY_HOMEPAGE'), 'homepage'); } else { $noErrors = true; } if (!$noErrors) { return $response; } } $values['name_checkbox_terms_of_use'] = isset($values['name_checkbox_terms_of_use']) ? (int) $values['name_checkbox_terms_of_use'] : 0; if ((!$user->authorise('comment.flood', 'com_jcomments')) && (JCommentsSecurity::checkFlood($userIP))) { self::showErrorMessage(Text::_('ERROR_TOO_QUICK')); } elseif (((int) $config->get('show_checkbox_terms_of_use') == 1) && ($values['name_checkbox_terms_of_use'] == 0) && ($acl->showTermsOfUse())) { self::showErrorMessage(Text::_('ERROR_CHECKBOX_TERMS_OF_USE_NO_SELECTED'), 'name_checkbox_terms_of_use'); } elseif (empty($values['homepage']) && ($config->get('author_homepage') == 3)) { self::showErrorMessage(Text::_('ERROR_EMPTY_HOMEPAGE'), 'homepage'); } elseif (empty($values['title']) && ($config->get('comment_title') == 3)) { self::showErrorMessage(Text::_('ERROR_EMPTY_TITLE'), 'title'); } elseif (empty($values['comment'])) { self::showErrorMessage(Text::_('ERROR_EMPTY_COMMENT'), 'comment'); } elseif (((int) $config->get('comment_maxlength') != 0) && (!$user->authorise('comment.length_check', 'com_jcomments')) && (StringHelper::strlen($values['comment']) > $config->get('comment_maxlength'))) { self::showErrorMessage(Text::_('ERROR_YOUR_COMMENT_IS_TOO_LONG'), 'comment'); } elseif (((int) $config->get('comment_minlength', 0) != 0) && (!$user->authorise('comment.length_check', 'com_jcomments')) && (StringHelper::strlen($values['comment']) < $config->get('comment_minlength'))) { self::showErrorMessage(Text::_('ERROR_YOUR_COMMENT_IS_TOO_SHORT'), 'comment'); } else { if (!$user->authorise('comment.captcha', 'com_jcomments')) { $captchaEngine = $config->get('captcha_engine', 'kcaptcha'); switch ($captchaEngine) { case 'kcaptcha': require_once JPATH_ROOT . '/components/com_jcomments/jcomments.captcha.php'; if (!JCommentsCaptcha::check($values['captcha_refid'])) { self::showErrorMessage(Text::_('ERROR_CAPTCHA'), 'captcha'); JCommentsCaptcha::destroy(); $response->addScript("jcomments.clear('captcha');"); return $response; } break; case 'recaptcha': case 'recaptcha_invisible': if ($captchaEngine == 'recaptcha') { PluginHelper::importPlugin('captcha', 'recaptcha'); } else { PluginHelper::importPlugin('captcha', 'recaptcha_invisible'); } try { $app->triggerEvent('onCheckAnswer'); } catch (Exception $e) { self::showErrorMessage($e->getMessage()); $response->addScript("grecaptcha.reset()"); return $response; } break; case 'hcaptcha': case 'hcaptcha_invisible': if ($captchaEngine == 'hcaptcha') { PluginHelper::importPlugin('captcha', 'hcaptcha'); } else { PluginHelper::importPlugin('captcha', 'hcaptcha_invisible'); } try { $app->triggerEvent('onCheckAnswer'); } catch (Exception $e) { self::showErrorMessage($e->getMessage()); $response->addScript("hcaptcha.reset()"); return $response; } break; case 'turnstile': PluginHelper::importPlugin('captcha', 'turnstile'); try { $app->triggerEvent('onCheckAnswer', array($app->input->getCmd('turnstile'))); } catch (Exception $e) { self::showErrorMessage($e->getMessage()); $response->addScript("turnstile.reset()"); return $response; } break; default: $result = JCommentsEvent::trigger('onJCommentsCaptchaVerify', array($values['captcha_refid'], &$response)); // If all plugins returns false if (!in_array(true, $result, true)) { self::showErrorMessage(Text::_('ERROR_CAPTCHA')); return $response; } } } /** @var DatabaseDriver $db */ $db = Factory::getContainer()->get('DatabaseDriver'); // Small fix (by default $my has empty 'name' and 'email' field) if ($user->get('id')) { $currentUser = Factory::getUser($user->get('id')); $user->name = $currentUser->name; $user->username = $currentUser->username; $user->email = $currentUser->email; unset($currentUser); } // Set user real name to 'Guest' for all languages. if (empty($values['name'])) { $values['name'] = 'Guest'; } $comment = Table::getInstance('Comment', 'JCommentsTable'); $comment->id = 0; $comment->name = $user->get('id') ? $user->name : preg_replace("/[\'\"\>\<\(\)\[\]]?+/i", '', $values['name']); $comment->username = $user->get('id') ? $user->username : $comment->name; $comment->email = $user->get('id') ? $user->email : ($values['email'] ?? ''); if (((int) $config->get('author_homepage') != 0) && !empty($values['homepage'])) { $comment->homepage = JCommentsText::url($values['homepage']); } $comment->comment = $values['comment']; // Filter forbidden bbcodes $bbcode = JCommentsFactory::getBBCode(); $comment->comment = $bbcode->filter($comment->comment); if ($comment->comment != '') { if ((int) $config->get('enable_custom_bbcode')) { // Filter forbidden custom bbcodes $commentLength = strlen($comment->comment); $customBBCode = JCommentsFactory::getCustomBBCode(); $comment->comment = $customBBCode->filter($comment->comment); if (strlen($comment->comment) == 0 && $commentLength > 0) { self::showErrorMessage(Text::_('ERROR_YOU_HAVE_NO_RIGHTS_TO_USE_THIS_TAG'), 'comment'); return $response; } } } if ($comment->comment == '') { self::showErrorMessage(Text::_('ERROR_EMPTY_COMMENT'), 'comment'); return $response; } $commentWithoutQuotes = $bbcode->removeQuotes($comment->comment); if ($commentWithoutQuotes == '') { self::showErrorMessage(Text::_('ERROR_NOTHING_EXCEPT_QUOTES'), 'comment'); return $response; } elseif (((int) $config->get('comment_minlength', 0) != 0) && (!$user->authorise('comment.length_check', 'com_jcomments')) && (StringHelper::strlen($commentWithoutQuotes) < $config->get('comment_minlength'))) { self::showErrorMessage(Text::_('ERROR_YOUR_COMMENT_IS_TOO_SHORT'), 'comment'); return $response; } $values['subscribe'] = isset($values['subscribe']) ? (int) $values['subscribe'] : 0; if ($values['subscribe'] == 1 && $comment->email == '') { self::showErrorMessage(Text::_('ERROR_SUBSCRIPTION_EMAIL'), 'email'); return $response; } $comment->object_id = (int) $objectID; $comment->object_group = $objectGroup; $comment->title = $values['title'] ?? ''; $comment->parent = isset($values['parent']) ? (int) $values['parent'] : 0; $comment->lang = $lang->getTag(); $comment->ip = $userIP; $comment->userid = $user->get('id') ?: 0; $comment->date = Factory::getDate()->toSql(); // Cast to integer value to store in DB. $comment->published = (int) $user->authorise('comment.autopublish', 'com_jcomments'); $query = $db->getQuery(true); $query ->select('COUNT(*)') ->from($db->quoteName('#__jcomments')) ->where($db->quoteName('comment') . ' = ' . $db->quote($comment->comment)) ->where($db->quoteName('ip') . ' = ' . $db->quote($comment->ip)) ->where($db->quoteName('name') . ' = ' . $db->quote($comment->name)) ->where($db->quoteName('userid') . ' = ' . $comment->userid) ->where($db->quoteName('object_id') . ' = ' . $comment->object_id) ->where($db->quoteName('parent') . ' = ' . $comment->parent) ->where($db->quoteName('object_group') . ' = ' . $db->quote($comment->object_group)); if (JCommentsFactory::getLanguageFilter()) { $query->where($db->quoteName('lang') . ' = ' . $db->quote($lang->getTag())); } $db->setQuery($query); try { $found = $db->loadResult(); } catch (RuntimeException $e) { $found = 0; Log::add($e->getMessage(), Log::ERROR, 'com_jcomments'); } // If duplicates is not found if ($found == 0) { $result = JCommentsEvent::trigger('onJCommentsCommentBeforeAdd', array(&$comment)); if (in_array(false, $result, true)) { return $response; } // Save comments subscription if ($values['subscribe']) { require_once JPATH_ROOT . '/components/com_jcomments/models/subscriptions.php'; $subscriptionModel = new JcommentsModelSubscriptions; $subscriptionModel->subscribe( $comment->object_id, $comment->object_group, $comment->userid, $comment->email, $comment->name, $comment->lang ); } $merged = false; $mergeTime = (int) $config->get('merge_time', 0); // Merge comments from same author if ($user->get('id') && $mergeTime > 0) { // Load previous comment for same object and group $prevComment = JCommentsModel::getLastComment($comment->object_id, $comment->object_group, $comment->parent); if ($prevComment != null) { // If previous comment from same author and it currently not edited // by any user - we'll update comment, else - insert new record to database if (($prevComment->userid == $comment->userid) && ($prevComment->parent == $comment->parent) && (!$acl->isLocked($prevComment))) { $newText = $prevComment->comment . '

' . $comment->comment; $timeDiff = strtotime($comment->date) - strtotime($prevComment->date); if ($timeDiff < $mergeTime) { $maxlength = (int) $config->get('comment_maxlength'); $needcheck = !$user->authorise('comment.length_check', 'com_jcomments'); // Validate new comment text length and if it longer than specified - // disable union current comment with previous if (($needcheck == 0) || (($needcheck == 1) && ($maxlength != 0) && (StringHelper::strlen($newText) <= $maxlength))) { $comment->id = $prevComment->id; $comment->comment = $newText; $merged = true; } } } unset($prevComment); } } // Save new comment to database if (!$comment->store()) { Log::add($comment->getError(), Log::ERROR, 'com_jcomments'); $response->addScript("jcomments.clear('comment');"); if (!$user->authorise('comment.captcha', 'com_jcomments')) { if ($config->get('captcha_engine', 'kcaptcha') == 'kcaptcha') { JCommentsCaptcha::destroy(); $response->addScript("jcomments.clear('captcha');"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'recaptcha') { $response->addScript("grecaptcha.reset()"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'turnstile') { $response->addScript("turnstile.reset()"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'hcaptcha') { $response->addScript("hcaptcha.reset()"); } } return $response; } // Store/update information about commented object JCommentsObject::storeObjectInfo($comment->object_id, $comment->object_group, $comment->lang); JCommentsEvent::trigger('onJCommentsCommentAfterAdd', array(&$comment)); // Send notification to administrators if ((int) $config->get('enable_notification') == 1) { if (in_array(1, $config->get('notification_type'))) { JComments::sendNotification($comment, true); } } // If comment published we need update comments list if ($comment->published) { // Send notification to comment subscribers JComments::sendToSubscribers($comment, true); if ($merged) { $commentText = $comment->comment; $html = JCommentsText::jsEscape(JComments::getCommentItem($comment)); $response->addScript("jcomments.updateComment(" . $comment->id . ", '$html');"); $comment->comment = $commentText; } else { $count = JComments::getCommentsCount($comment->object_id, $comment->object_group); if ($config->get('template_view') == 'tree') { if ($count > 1) { $html = JComments::getCommentListItem($comment); $html = JCommentsText::jsEscape($html); $mode = ((int) $config->get('comments_tree_order') == 1 || ((int) $config->get('comments_tree_order') == 2 && $comment->parent > 0)) ? 'b' : 'a'; $response->addScript("jcomments.updateTree('$html','$comment->parent','$mode');"); } else { $html = JComments::getCommentsTree($comment->object_id, $comment->object_group); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateTree('$html',null);"); } } else { // If pagination disabled and comments count > 1... if ((int) $config->get('comments_per_page') == 0 && $count > 1) { // Update only added comment $html = JComments::getCommentListItem($comment); $html = JCommentsText::jsEscape($html); if ($config->get('comments_list_order') == 'DESC') { $response->addScript("jcomments.updateList('$html','p');"); } else { $response->addScript("jcomments.updateList('$html','a');"); } } else { // Update comments list $html = JComments::getCommentsList( $comment->object_id, $comment->object_group, JComments::getCommentPage($comment->object_id, $comment->object_group, $comment->id) ); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateList('$html','r');"); } // Scroll to first comment if ($config->get('comments_list_order') == 'DESC') { $response->addScript("jcomments.scrollToList();"); } } } self::showInfoMessage(Text::_('THANK_YOU_FOR_YOUR_SUBMISSION')); } else { self::showInfoMessage(Text::_('THANK_YOU_YOUR_COMMENT_WILL_BE_PUBLISHED_ONCE_REVIEWED')); } // Clear comments textarea & update comment length counter if needed $response->addScript("jcomments.clear('comment');"); if (!$user->authorise('comment.captcha', 'com_jcomments')) { if ($config->get('captcha_engine', 'kcaptcha') == 'kcaptcha') { require_once JPATH_ROOT . '/components/com_jcomments/jcomments.captcha.php'; JCommentsCaptcha::destroy(); $response->addScript("jcomments.clear('captcha');"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'recaptcha') { $response->addScript("grecaptcha.reset();"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'turnstile') { $response->addScript("turnstile.reset();"); } elseif ($config->get('captcha_engine', 'kcaptcha') == 'hcaptcha') { $response->addScript("hcaptcha.reset();"); } } } else { self::showErrorMessage(Text::_('ERROR_DUPLICATE_COMMENT'), 'comment'); } } } else { $message = Text::_('ERROR_CANT_COMMENT'); if ($acl->getUserBlocked()) { $bannedMessage = JCommentsText::getMessagesBasedOnLanguage($config->get('messages_fields'), 'message_banned', $lang->getTag()); if (!empty($bannedMessage)) { $message = self::escapeMessage($bannedMessage); } } $response->addAlert($message); } return $response; } public static function deleteComment($id) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $acl = JCommentsFactory::getACL(); $config = ComponentHelper::getParams('com_jcomments'); $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { if ($acl->isLocked($comment)) { $response->addAlert(Text::_('ERROR_BEING_EDITTED')); } elseif ($acl->canDelete($comment)) { $objectID = $comment->object_id; $objectGroup = $comment->object_group; $result = JCommentsEvent::trigger('onJCommentsCommentBeforeDelete', array(&$comment)); if (!in_array(false, $result, true)) { if ((int) $config->get('delete_mode') == 0) { $comment->delete(); $count = JComments::getCommentsCount($objectID, $objectGroup); if ($config->get('template_view') == 'tree') { if ($count > 0) { $response->addScript("jcomments.updateComment('$id','');"); } else { $response->addScript("jcomments.updateTree('',null);"); } } else { if ($count > 0) { if ((int) $config->get('comments_per_page') > 0) { require_once JPATH_ROOT . '/components/com_jcomments/helpers/pagination.php'; $pagination = new JCommentsPagination($objectID, $objectGroup); $pagination->setCommentsCount($count); $currentPage = $pagination->getCommentPage($objectID, $objectGroup, $id); $currentPage = min($currentPage, $pagination->getTotalPages()); $html = JComments::getCommentsList($objectID, $objectGroup, $currentPage); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateList('$html','r');"); } else { $response->addScript("jcomments.updateComment('$id','');"); } } else { $response->addScript("jcomments.updateList('','r');"); } } } else { $comment->markAsDeleted(); $html = JCommentsText::jsEscape(JComments::getCommentItem($comment)); $response->addScript("jcomments.updateComment(" . $comment->id . ", '$html');"); } JCommentsEvent::trigger('onJCommentsCommentAfterDelete', array(&$comment)); } } else { $response->addAlert(Text::_('ERROR_CANT_DELETE')); } } return $response; } /** * Publish or unpublish comment * * @param integer $id Comment ID * * @return JoomlaTuneAjaxResponse|null * * @see JCommentsPublishComment * @since 3.0 */ public static function publishComment($id) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $acl = JCommentsFactory::getACL(); $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { if ($acl->isLocked($comment)) { $response->addAlert(Text::_('ERROR_BEING_EDITTED')); } elseif ($acl->canPublish($comment)) { $objectID = $comment->object_id; $objectGroup = $comment->object_group; $page = JComments::getCommentPage($objectID, $objectGroup, $comment->id); $comment->published = $comment->published == 1 ? 0 : 1; $result = JCommentsEvent::trigger('onJCommentsCommentBeforePublish', array(&$comment)); if (!in_array(false, $result, true)) { if ($comment->store()) { JCommentsEvent::trigger('onJCommentsCommentAfterPublish', array(&$comment)); if ($comment->published) { JComments::sendToSubscribers($comment); } self::updateCommentsList($response, $objectID, $objectGroup, $page); } } } else { $response->addAlert(Text::_('ERROR_CANT_PUBLISH')); } } return $response; } public static function cancelComment($id) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { $acl = JCommentsFactory::getACL(); if (!$acl->isLocked($comment)) { $comment->checkin(); } } return $response; } public static function editComment($id, $loadForm = 0) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $user = Factory::getUser(); $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { $acl = JCommentsFactory::getACL(); if ($acl->isLocked($comment)) { $response->addAlert(Text::_('ERROR_BEING_EDITTED')); } elseif ($acl->canEdit($comment)) { $comment->checkout($user->id); $name = ($comment->userid) ? '' : JCommentsText::jsEscape($comment->name); $email = ($comment->userid) ? '' : JCommentsText::jsEscape($comment->email); $homepage = JCommentsText::jsEscape($comment->homepage); $text = JCommentsText::jsEscape(JCommentsText::br2nl($comment->comment)); $title = JCommentsText::jsEscape(str_replace("\n", '', JCommentsText::br2nl($comment->title))); if ((int) $loadForm == 1) { $form = JComments::getCommentsForm($comment->object_id, $comment->object_group); $response->addAssign('comments-form-link', 'innerHTML', $form); } $response->addScript("jcomments.showEdit(" . $comment->id . ", '$name', '$email', '$homepage', '$title', '$text');"); } else { $response->addAlert(Text::_('ERROR_CANT_EDIT')); } } return $response; } public static function saveComment($values = array()) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $config = ComponentHelper::getParams('com_jcomments'); $user = Factory::getApplication()->getIdentity(); $response = JCommentsFactory::getAjaxResponse(); $values = self::prepareValues($_POST); // TODO $values from function or from method? $comment = Table::getInstance('Comment', 'JCommentsTable'); $id = (int) $values['id']; if ($comment->load($id)) { $acl = JCommentsFactory::getACL(); $values['name_checkbox_terms_of_use'] = isset($values['name_checkbox_terms_of_use']) ? (int) $values['name_checkbox_terms_of_use'] : 0; if ($acl->canEdit($comment)) { if ($values['comment'] == '') { self::showErrorMessage(Text::_('ERROR_EMPTY_COMMENT'), 'comment'); } elseif (((int) $config->get('show_checkbox_terms_of_use') == 1) && ($values['name_checkbox_terms_of_use'] == 0) && ($acl->showTermsOfUse())) { self::showErrorMessage(Text::_('ERROR_CHECKBOX_TERMS_OF_USE_NO_SELECTED'), 'name_checkbox_terms_of_use'); } elseif (((int) $config->get('comment_maxlength') != 0) && (!$user->authorise('comment.length_check', 'com_jcomments')) && (StringHelper::strlen($values['comment']) > (int) $config->get('comment_maxlength'))) { self::showErrorMessage(Text::_('ERROR_YOUR_COMMENT_IS_TOO_LONG'), 'comment'); } elseif (((int) $config->get('comment_minlength') != 0) && (!$user->authorise('comment.length_check', 'com_jcomments')) && (StringHelper::strlen($values['comment']) < (int) $config->get('comment_minlength'))) { self::showErrorMessage(Text::_('ERROR_YOUR_COMMENT_IS_TOO_SHORT'), 'comment'); } else { $bbcode = JCommentsFactory::getBBCode(); $comment->comment = $values['comment']; $comment->comment = $bbcode->filter($comment->comment); $comment->published = (int) $user->authorise('comment.autopublish', 'com_jcomments'); if (((int) $config->get('comment_title') != 0) && isset($values['title'])) { $comment->title = stripslashes((string) $values['title']); } if (((int) $config->get('author_homepage') == 1) && isset($values['homepage'])) { $comment->homepage = JCommentsText::url($values['homepage']); } else { $comment->homepage = ''; } $result = JCommentsEvent::trigger('onJCommentsCommentBeforeChange', array(&$comment)); if (in_array(false, $result, true)) { return $response; } if ($comment->store()) { $comment->checkin(); JCommentsEvent::trigger('onJCommentsCommentAfterChange', array(&$comment)); if ((int) $config->get('enable_notification') == 1) { if (in_array(1, $config->get('notification_type'))) { JComments::sendNotification($comment, false); } } $html = JCommentsText::jsEscape(JComments::getCommentItem($comment)); $response->addScript("jcomments.updateComment(" . $comment->id . ", '$html');"); } else { Log::add($comment->getError(), Log::ERROR, 'com_jcomments'); $response->addAlert(Text::_('JERROR_AN_ERROR_HAS_OCCURRED')); } } } else { $response->addAlert(Text::_('ERROR_CANT_EDIT')); } } return $response; } public static function quoteComment($id, $loadForm = 0) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $user = Factory::getApplication()->getIdentity(); $acl = JCommentsFactory::getACL(); $config = ComponentHelper::getParams('com_jcomments'); $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { $commentName = JCommentsContent::getCommentAuthorName($comment); $commentText = JCommentsText::br2nl($comment->comment); if ((int) $config->get('enable_nested_quotes') == 0) { $bbcode = JCommentsFactory::getBBCode(); $commentText = $bbcode->removeQuotes($commentText); } if ((int) $config->get('enable_custom_bbcode')) { $customBBCode = JCommentsFactory::getCustomBBCode(); $commentText = $customBBCode->filter($commentText, true); } if ($user->get('id') == 0) { $bbcode = JCommentsFactory::getBBCode(); $commentText = $bbcode->removeHidden($commentText); } if ($commentText != '') { if ($acl->enableAutocensor()) { $commentText = JCommentsText::censor($commentText); } if ((int) $loadForm == 1) { $form = JComments::getCommentsForm($comment->object_id, $comment->object_group); $response->addAssign('comments-form-link', 'innerHTML', $form); } $commentName = JCommentsText::jsEscape($commentName); $commentText = JCommentsText::jsEscape($commentText); $text = '[quote name="' . $commentName . '"]' . $commentText . '[/quote]\n'; $response->addScript("jcomments.insertText('" . $text . "');"); } else { $response->addAlert(Text::_('ERROR_NOTHING_TO_QUOTE')); } } return $response; } public static function updateCommentsList($response, $objectID, $objectGroup, $page) { $config = ComponentHelper::getParams('com_jcomments'); if ($config->get('template_view') == 'tree') { $html = JComments::getCommentsTree($objectID, $objectGroup, $page); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateTree('$html',null);"); } else { $html = JComments::getCommentsList($objectID, $objectGroup, $page); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateList('$html','r');"); } } public static function showPage($objectID, $objectGroup, $page) { $response = JCommentsFactory::getAjaxResponse(); $objectID = (int) $objectID; $objectGroup = strip_tags($objectGroup); $objectGroup = JCommentsSecurity::clearObjectGroup($objectGroup); $page = (int) $page; self::updateCommentsList($response, $objectID, $objectGroup, $page); return $response; } public static function showComment($id) { $response = JCommentsFactory::getAjaxResponse(); $acl = JCommentsFactory::getACL(); $config = ComponentHelper::getParams('com_jcomments'); $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id) && ($acl->canPublish($comment) || $comment->published)) { if ($config->get('template_view') == 'tree') { $page = 0; } else { $page = JComments::getCommentPage($comment->object_id, $comment->object_group, $comment->id); } self::updateCommentsList($response, $comment->object_id, $comment->object_group, $page); $response->addScript("jcomments.scrollToComment('$id');"); } else { $response->addAlert(Text::_('ERROR_NOT_FOUND')); } return $response; } /** * Search for email and simulate click on mailto: link. * @param integer $id Comment ID. * @param string $hash Email hash. * @param boolean $email Search and replace only in email address, in comment text otherwise. * * @return JoomlaTuneAjaxResponse * * @since 3.0 */ public static function jump2email($id, $hash, $email = false) { $response = JCommentsFactory::getAjaxResponse(); $comment = Table::getInstance('Comment', 'JCommentsTable'); $hash = preg_replace('#[\(\)\'\"]#is', '', strip_tags($hash)); if ((strlen($hash) == 32) && ($comment->load((int) $id))) { $matches = array(); preg_match_all(_JC_REGEXP_EMAIL, ($email ? $comment->email : $comment->comment), $matches); foreach ($matches[0] as $email) { if (md5((string) $email) == $hash) { $response->addScript("window.location='mailto:$email';"); } } } return $response; } public static function voteComment($id, $value) { /** @var DatabaseDriver $db */ $db = Factory::getContainer()->get('DatabaseDriver'); $user = Factory::getApplication()->getIdentity(); $acl = JCommentsFactory::getACL(); $response = JCommentsFactory::getAjaxResponse(); $value = (int) $value; $value = ($value > 0) ? 1 : -1; $ip = $_SERVER['REMOTE_ADDR']; $query = $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName('#__jcomments_votes')) ->where($db->quoteName('commentid') . ' = ' . (int) $id); if ($user->get('id')) { $query->where($db->quoteName('userid') . ' = ' . $user->get('id')); } else { $query->where($db->quoteName('userid') . ' = 0') ->where($db->quoteName('ip') . ' = ' . $db->quote($ip)); } $db->setQuery($query); try { $voted = $db->loadResult(); } catch (RuntimeException $e) { Log::add($e->getMessage(), Log::ERROR, 'com_jcomments'); $response->addAlert(Text::_('ERROR_CANT_VOTE')); return $response; } if ($voted == 0) { /** @var JCommentsTableComment $comment */ $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { if ($acl->canVote($comment)) { $result = JCommentsEvent::trigger('onJCommentsCommentBeforeVote', array(&$comment, &$value)); if (!in_array(false, $result, true)) { if ($value > 0) { $comment->isgood++; } else { $comment->ispoor++; } if (!$comment->store()) { Log::add($comment->getError(), Log::ERROR, 'com_jcomments'); $response->addAlert(Text::_('ERROR_CANT_VOTE')); return $response; } $now = Factory::getDate()->toSql(); $query = $db->getQuery(true) ->insert($db->quoteName('#__jcomments_votes')) ->columns( array( $db->quoteName('commentid'), $db->quoteName('userid'), $db->quoteName('ip'), $db->quoteName('date'), $db->quoteName('value') ) ) ->values( $db->quote($comment->id) . ', ' . $db->quote($user->get('id')) . ', ' . $db->quote($ip) . ', ' . $db->quote($now) . ', ' . $value ); $db->setQuery($query); try { $db->execute(); } catch (RuntimeException $e) { Log::add($comment->getError(), Log::ERROR, 'com_jcomments'); $response->addAlert(Text::_('ERROR_CANT_VOTE')); return $response; } JCommentsEvent::trigger('onJCommentsCommentAfterVote', array(&$comment, $value)); } $tmpl = JCommentsFactory::getTemplate(); $tmpl->load('tpl_comment'); $tmpl->addVar('tpl_comment', 'get_comment_vote', 1); $tmpl->addObject('tpl_comment', 'comment', $comment); $html = $tmpl->renderTemplate('tpl_comment'); $html = JCommentsText::jsEscape($html); $response->addScript("jcomments.updateVote('" . $comment->id . "','$html');"); } else { $response->addAlert(Text::_('ERROR_CANT_VOTE')); } } else { $response->addAlert(Text::_('ERROR_NOT_FOUND')); } } else { $response->addAlert(Text::_('ERROR_ALREADY_VOTED')); } return $response; } public static function reportComment() { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } /** @var DatabaseDriver $db */ $db = Factory::getContainer()->get('DatabaseDriver'); $app = Factory::getApplication(); $acl = JCommentsFactory::getACL(); $config = ComponentHelper::getParams('com_jcomments'); $response = JCommentsFactory::getAjaxResponse(); $user = $app->getIdentity(); $id = $app->input->getInt('commentid'); $reason = $app->input->getString('reason'); $name = $app->input->getString('name'); $ip = $_SERVER['REMOTE_ADDR']; if (empty($reason)) { if ((int) $config->get('report_reason_required') == 1) { self::showErrorMessage(Text::_('ERROR_NO_REASON_FOR_REPORT'), '', 'comments-report-form'); return $response; } else { $reason = Text::_('REPORT_REASON_UNKNOWN_REASON'); } } $query = $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName('#__jcomments_reports')) ->where($db->quoteName('commentid') . ' = ' . $id); if ($user->get('id')) { $query->where($db->quoteName('userid') . ' = ' . $user->get('id')); } else { $query->where($db->quoteName('userid') . ' = 0') ->where($db->quoteName('ip') . ' = ' . $db->quote($ip)); } $db->setQuery($query); $reported = $db->loadResult(); if (!$reported) { $maxReportsPerComment = (int) $config->get('reports_per_comment', 1); $maxReportsBeforeUnpublish = (int) $config->get('reports_before_unpublish', 0); $query->clear() ->select('COUNT(*)') ->from($db->quoteName('#__jcomments_reports')) ->where($db->quoteName('commentid') . ' = ' . $id); $db->setQuery($query); $reported = $db->loadResult(); if ($reported < $maxReportsPerComment || $maxReportsPerComment == 0) { $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load($id)) { if ($acl->canReport($comment)) { if ($user->get('id')) { $name = $user->get('name'); } else { if (empty($name)) { $name = 'Guest'; } } $report = Table::getInstance('Report', 'JCommentsTable'); $report->commentid = $comment->id; $report->date = Factory::getDate()->toSql(); $report->userid = $user->get('id'); $report->ip = $ip; $report->name = $name; $report->reason = $reason; $html = ''; $result = JCommentsEvent::trigger('onJCommentsCommentBeforeReport', array(&$comment, &$report)); if (!in_array(false, $result, true)) { if ($report->store()) { JCommentsEvent::trigger('onJCommentsCommentAfterReport', array(&$comment, $report)); if ((int) $config->get('enable_notification') == 1) { if (in_array(2, $config->get('notification_type'))) { JComments::sendReport($comment, $name, $reason); } } // Unpublish comment if reports count is enough if ($maxReportsBeforeUnpublish > 0 && $reported >= $maxReportsBeforeUnpublish) { $comment->published = 0; $comment->store(); } $html = Text::_('REPORT_SUCCESSFULLY_SENT'); $html = str_replace("\n", '\n', $html); $html = str_replace('\n', '
', $html); $html = JCommentsText::jsEscape($html); } } $response->addScript("jcomments.closeReport('$html');"); } else { self::showErrorMessage(Text::_('ERROR_YOU_HAVE_NO_RIGHTS_TO_REPORT'), '', 'comments-report-form'); } } else { $response->addAlert(Text::_('ERROR_NOT_FOUND')); } } else { self::showErrorMessage(Text::_('ERROR_COMMENT_ALREADY_REPORTED'), '', 'comments-report-form'); } } else { self::showErrorMessage(Text::_('ERROR_YOU_CAN_NOT_REPORT_THE_SAME_COMMENT_MORE_THAN_ONCE'), '', 'comments-report-form'); } return $response; } public static function BanIP($id) { if (JCommentsSecurity::badRequest() == 1) { JCommentsSecurity::notAuth(); } $acl = JCommentsFactory::getACL(); $response = JCommentsFactory::getAjaxResponse(); if ($acl->canBan()) { $config = ComponentHelper::getParams('com_jcomments'); if ((int) $config->get('enable_blacklist') == 1) { $comment = Table::getInstance('Comment', 'JCommentsTable'); if ($comment->load((int) $id)) { // We will not ban own IP ;) if ($comment->ip != $_SERVER['REMOTE_ADDR']) { $options = array(); $options['ip'] = $comment->ip; // Check if this IP already banned if (JCommentsSecurity::checkBlacklist($options)) { $result = JCommentsEvent::trigger('onJCommentsUserBeforeBan', array(&$comment, &$options)); if (!in_array(false, $result, true)) { $blacklist = Table::getInstance('Blacklist', 'JCommentsTable'); $blacklist->ip = $comment->ip; $blacklist->created = Factory::getDate()->toSql(); $blacklist->created_by = Factory::getApplication()->getIdentity()->get('id'); if ($blacklist->store()) { JCommentsEvent::trigger('onJCommentsUserAfterBan', array(&$comment, $options)); self::showInfoMessage(Text::_('SUCCESSFULLY_BANNED'), 'comment-item-' . (int) $id); } } } else { self::showErrorMessage(Text::_('ERROR_IP_ALREADY_BANNED'), '', 'comment-item-' . (int) $id); } } else { self::showErrorMessage(Text::_('ERROR_YOU_CAN_NOT_BAN_YOUR_IP'), '', 'comment-item-' . (int) $id); } } } } return $response; } public static function refreshObjectsAjax() { $app = Factory::getApplication(); $hash = $app->input->post->get('hash', ''); $step = $app->input->post->getInt('step'); $lang = $app->input->post->get('lang', ''); if ($hash === md5($app->get('secret'))) { /** @var DatabaseDriver $db * */ $db = Factory::getContainer()->get('DatabaseDriver'); if ($step == 0) { if ($app->get('caching') != 0) { // Clean cache for all object groups $query = $db->getQuery(true) ->select('DISTINCT ' . $db->quoteName('object_group')) ->from($db->quoteName('#__jcomments_objects')); $db->setQuery($query); $rows = $db->loadColumn(); foreach ($rows as $row) { /** @var CallbackController $cache */ $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) ->createCacheController('callback', ['defaultgroup' => 'com_jcomments_objects_' . strtolower($row)]); /** @var Cache $cache */ $cache->clean(); } } $db->setQuery('TRUNCATE TABLE ' . $db->quoteName('#__jcomments_objects')); $db->execute(); } // Count objects without information $query = $db->getQuery(true) ->clear() ->select('COUNT(DISTINCT ' . $db->quoteName('c.object_id') . ', ' . $db->quoteName('c.object_group') . ', ' . $db->quoteName('c.lang') . ')') ->from($db->quoteName('#__jcomments', 'c')) ->where('IFNULL(' . $db->quoteName('c.lang') . ', "") <> ""'); $db->setQuery($query); $total = (int) $db->loadResult(); $count = 0; if ($total > 0) { // Get list of first objects without information $query = $db->getQuery(true) ->select('DISTINCT ' . $db->quoteName('c.object_id') . ', ' . $db->quoteName('c.object_group') . ', ' . $db->quoteName('c.lang')) ->from($db->quoteName('#__jcomments', 'c')) ->where('IFNULL(' . $db->quoteName('c.lang') . ', "") <> ""'); $subquery = $db->getQuery(true) ->select($db->quoteName('o.id')) ->from($db->quoteName('#__jcomments_objects', 'o')) ->where($db->quoteName('o.object_id') . ' = ' . $db->quoteName('c.object_id')) ->where($db->quoteName('o.object_id') . ' = ' . $db->quoteName('c.object_group')) ->where($db->quoteName('o.object_id') . ' = ' . $db->quoteName('c.lang')); $query->where('NOT EXISTS (' . $subquery . ')') ->order($db->quoteName(array('c.object_group', 'c.lang'))); $db->setQuery($query, 0, $count); $rows = $db->loadObjectList(); $i = 0; $multilanguage = JCommentsFactory::getLanguageFilter(); $nextLanguage = $lang; if (count($rows)) { foreach ($rows as $row) { if ($nextLanguage != $row->lang && $multilanguage) { $nextLanguage = $row->lang; break; } // Retrieve and store object information JCommentsObject::storeObjectInfo($row->object_id, $row->object_group, $row->lang, false, true); $i++; } } if ($i > 0) { $query = $db->getQuery(true) ->select('COUNT(id)') ->from($db->quoteName('#__jcomments_objects')); $db->setQuery($query); $count = (int) $db->loadResult(); } $percent = ceil(($count / $total) * 100); $percent = min($percent, 100); } else { $percent = 100; } $step++; $langCodes = LanguageHelper::getLanguages('lang_code'); $languageSef = isset($langCodes[$nextLanguage]) ? $langCodes[$nextLanguage]->sef : $nextLanguage; $data = array( 'count' => $count, 'total' => $total, 'percent' => $percent, 'step' => $step, 'hash' => $hash, 'object_group' => null, 'lang' => $nextLanguage, 'lang_sef' => $languageSef ); echo json_encode($data); } $app->close(); } } $result = ob_get_contents(); ob_end_clean();