$comments_max_characters) { $body = substr($body, 0, $comments_max_characters); // just in case not caught in submit form } $parent_ref = getval("ref_parent", 0, true); $collection_ref = getval("collection_ref", 0, true); $resource_ref = getval("resource_ref", 0, true); $sql_values_prepend = array( "i", ($parent_ref == 0 ? null : (int)$parent_ref), "i", ($collection_ref == 0 ? null : (int)$collection_ref), "i", ($resource_ref == 0 ? null : (int)$resource_ref) ); $sql_values = array_merge($sql_values_prepend, $sql_values, array("s",$body)); ps_query("insert into comment (ref_parent, collection_ref, resource_ref, {$sql_fields}, body) values (" . ps_param_insert(count($sql_values) / 2) . ")", $sql_values); // Notify anyone tagged. comments_notify_tagged($body, $userref, $resource_ref, $collection_ref); } /** * Check all comments that are children of the comment ref provided. If there is a branch made up entirely of hidden comments then remove the branch. * * @param int $ref Ref of the comment that is being deleted. * * @return int Number of child comments that are not hidden. */ function clean_comment_tree($ref) { $all_comments = ps_query("SELECT " . columns_in("comment") . " FROM comment WHERE ref_parent = ?", ['i', $ref]); $remaining = 0; if (count($all_comments) > 0) { foreach ($all_comments as $comment) { $remaining += clean_comment_tree($comment['ref']); if ($remaining == 0 && $comment['hide'] == 1) { ps_query("DELETE FROM comment WHERE ref = ?", ['i', $comment['ref']]); } } } $remaining += ps_value("SELECT count(*) as `value` FROM comment WHERE ref_parent = ? and hide = 0", ['i', $ref], 0); if ($remaining == 0) { ps_query("DELETE FROM comment WHERE hide = 1 and ref = ?", ['i', $ref]); } return $remaining; } /** * Find the root of a comment tree that the ref provided is a part of * * @param int $ref ref of a comment * * @return int|null ref of the root comment or null if the comment tree has been completely removed / the comment being checked has already been deleted. */ function find_root_comment($ref) { $comment = ps_query('SELECT ref, ref_parent FROM comment WHERE ref = ?', ['i', $ref]); if (is_array($comment) && !empty($comment)) { $comment = $comment[0]; if (!empty($comment['ref_parent'])) { return find_root_comment($comment['ref_parent']); } return $comment['ref']; } return null; } /** * Parse a comment and replace and add links to any user, resource and collection tags * * @param string $text The input text e.g. the body of the comment * */ function comments_tags_to_links($text): string { global $baseurl_short; $text = preg_replace('/@(\S+)/s', '@$1', $text); $text = preg_replace('/r([0-9]{1,})/si', 'r$1', $text); # r12345 to resource link $text = preg_replace('/c([0-9]{1,})/si', 'c$1', $text); # c12345 to collection link $text = str_replace("[BASEURLSHORT]", $baseurl_short, $text); // Replacing this earlier can cause issues return $text; } /** * Display all comments for a resource or collection * * @param integer $ref The reference of the resource, collection or the comment (if called from itself recursively) * @param boolean $bcollection_mode false == show comments for resources, true == show comments for collection * @param boolean $bRecursive Recursively show comments, defaults to true, will be set to false if depth limit reached * @param integer $level Used for recursion for display indentation etc. * * @return void */ function comments_show($ref, $bcollection_mode = false, $bRecursive = true, $level = 1) { if (!is_numeric($ref)) { return false; } global $baseurl_short, $username, $anonymous_login, $lang, $comments_max_characters, $comments_flat_view, $regex_email, $comments_show_anonymous_email_address; $anonymous_mode = (empty($username) || $username == $anonymous_login); // show extra fields if commenting anonymously if ($comments_flat_view) { $bRecursive = false; } $bRecursive = $bRecursive && ($level < $GLOBALS['comments_responses_max_level']); // set 'name' to either user.fullname, comment.fullname or default 'Anonymous' $sql = "select c.ref thisref, c.ref_parent, c.hide, c.created, c.body, c.website_url, c.email, u.username, u.ref, u.profile_image, parent.created 'responseToDateTime', " . "IFNULL(IFNULL(c.fullname, u.fullname), ?) 'name' ," . "IFNULL(IFNULL(parent.fullname, uparent.fullname), ?) 'responseToName' " . "from comment c left join (user u) on (c.user_ref = u.ref) left join (comment parent) on (c.ref_parent = parent.ref) left join (user uparent) on (parent.user_ref = uparent.ref) "; $sql_values = [ 's', $lang['comments_anonymous-user'], 's', $lang['comments_anonymous-user'], ]; $collection_ref = ($bcollection_mode) ? $ref : ""; $resource_ref = ($bcollection_mode) ? "" : $ref; $collection_mode = $bcollection_mode ? "collection_mode=true" : ""; if ($level == 1) { // pass this JS function the "this" from the submit button in a form to post it via AJAX call, then refresh the "comments_container" echo<<
EOT; generateFormToken("comment_form"); hook("beforecommentbody"); $api_native_csrf_gu = generate_csrf_data_for_api_native_authmode('get_users'); echo << EOT; if ($anonymous_mode) { echo << EOT; } $validateFunction = $anonymous_mode ? "if (validateAnonymousComment(this.parentNode))" : "if (validateComment(this.parentNode))"; echo<<
EOT; $sql .= $bcollection_mode ? "where c.collection_ref=?" : "where c.resource_ref=?"; // first level will look for either collection or resource comments $sql_values = array_merge($sql_values, array("i",$ref)); if (!$comments_flat_view) { $sql .= " and c.ref_parent is NULL"; } } else { $sql .= "where c.ref_parent=?"; // look for child comments, regardless of what type of comment $sql_values = array_merge($sql_values, array("i",$ref)); } $sql .= " order by c.created desc"; $found_comments = ps_query($sql, $sql_values); foreach ($found_comments as $comment) { $thisRef = $comment['thisref']; echo "
"; // indent for levels - this will always be zero if config $comments_flat_view=true # ----- Information line hook("beforecommentinfo", "all", array("ref" => $comment["ref"])); echo "
"; echo "
"; if ($comment['profile_image'] != "" && $anonymous_mode != true) { echo "
"; } echo "
"; if (empty($comment['name'])) { $comment['name'] = $comment['username']; } if ($anonymous_mode) { echo "
" . escape($comment['name']) . "
"; } else { echo "
" . escape($comment['name']) . "
"; } if ($comments_show_anonymous_email_address && !empty($comment['email'])) { echo "
" . escape($comment['email']) . "
"; } if (!empty($comment['website_url'])) { echo "
" . escape($comment['website_url']) . "
"; } echo "
"; echo "
" . date("D", strtotime($comment["created"])) . " " . nicedate($comment["created"], true, true, true) . " "; echo "
"; // end of CommentEntryInfoDetails echo "
"; // end of CommentEntryInfoLine echo "
"; // end CommentEntryInfoContainer echo "
"; if ($comment['hide']) { if (text("comments_removal_message") != "") { echo text("comments_removal_message"); } else { echo "[" . escape($lang["deleted"]) . "]"; } } else { echo comments_tags_to_links(escape($comment['body'])); } echo "
"; # ----- Form area $validateFunction = $anonymous_mode ? "if (validateAnonymousFlag(this.parentNode))" : "if (validateFlag(this.parentNode))"; if (!getval("comment{$thisRef}flagged", "")) { echo<<
EOT; } if (!$comment['hide']) { $respond_button_id = "comment_respond_button_" . $thisRef; $respond_div_id = "comment_respond_" . $thisRef; echo ""; // end respond echo "
"; if (getval("comment{$thisRef}flagged", "")) { echo '
' . escape($lang['comments_flag-has-been-flagged']) . '
'; } else { echo<< {$lang['comments_flag-this-comment']}
EOT; } if (checkPerm("o")) { ?>
 ' . $lang['comments_hide-comment-text-link']; ?>
"; // end of CommentEntryInfoFlag } echo "
"; // end of CommentEntry if ($bRecursive) { comments_show($thisRef, $bcollection_mode, true, $level + 1); } } if ($level == 1) { echo ""; // end of comments_container } } /** * Notify anyone tagged when a new comment is posted * * @param string $comment The comment body * @param integer $from_user Who posted the comment * @param integer $resource If commenting on a resource, the resource ID * @param integer $collection If commenting on a collection, the collection ID * * @return void */ function comments_notify_tagged($comment, $from_user, $resource = null, $collection = null) { // Find tagged users. $success = preg_match_all("/@.*? /", $comment . " ", $tagged, PREG_PATTERN_ORDER); if (!$success) { return true; } // Nothing to do, return out. foreach ($tagged[0] as $tag) { $tag = substr($tag, 1); $tag = trim($tag); // Get just the username. $user = get_user_by_username($tag); // Find the matching user ID // No match but there's an underscore? Try replacing the underscore with a space and search again. Spaces are swapped to underscores when tagging. if ($user === false) { $user = get_user_by_username(str_replace("_", " ", $tag)); } if ($user > 0) { // Notify them. // Build a URL based on whether this is a resource or collection global $baseurl,$userref,$lang; $url = $baseurl . "/?" . (is_null($resource) ? "c" : "r") . "=" . (is_null($resource) ? $collection : $resource); // Send the message. message_add(array($user), $lang["tagged_notification"] . " " . $comment, $url, $userref); } } return true; }