tag is in */ public $page = null; /** * @var Integer: total amount of comments by distinct commenters that the * current page has */ public $commentTotal = 0; /** * @var String: text of the current comment */ public $text = null; /** * Date when the comment was posted * * @var null */ public $date = null; /** * @var Integer: internal ID number (Comments.CommentID DB field) of the * current comment that we're dealing with */ public $id = 0; /** * @var Integer: ID of the parent comment, if this is a child comment */ public $parentID = 0; /** * The current vote from this user on this comment * * @var int|boolean: false if no vote, otherwise -1, 0, or 1 */ public $currentVote = false; /** * @var string: comment score (SUM() of all votes) of the current comment */ public $currentScore = '0'; /** * Username of the user who posted the comment * * @var string */ public $username = ''; /** * IP of the comment poster * * @var string */ public $ip = ''; /** * ID of the user who posted the comment * * @var int */ public $userID = 0; /** * The amount of points the user has; fetched from the user_stats table if * SocialProfile is installed, otherwise this remains 0 * * @var int */ public $userPoints = 0; /** * Comment ID of the thread this comment is in * this is the ID of the parent comment if there is one, * or this comment if there is not * Used for sorting * * @var null */ public $thread = null; /** * Unix timestamp when the comment was posted * Used for sorting * Processed from $date * * @var null */ public $timestamp = null; /** * Constructor - set the page ID * * @param CommentsPage $page ID number of the current page * @param IContextSource|null $context * @param array $data Straight from the DB about the comment */ public function __construct( CommentsPage $page, $context = null, $data ) { $this->page = $page; $this->setContext( $context ); $this->username = $data['Comment_Username']; $this->ip = $data['Comment_IP']; $this->text = $data['Comment_Text']; $this->date = $data['Comment_Date']; $this->userID = (int)$data['Comment_user_id']; $this->userPoints = $data['Comment_user_points']; $this->id = (int)$data['CommentID']; $this->parentID = (int)$data['Comment_Parent_ID']; $this->thread = $data['thread']; $this->timestamp = $data['timestamp']; if ( isset( $data['current_vote'] ) ) { $vote = $data['current_vote']; } else { $dbr = wfGetDB( DB_REPLICA ); $row = $dbr->selectRow( 'Comments_Vote', [ 'Comment_Vote_Score' ], [ 'Comment_Vote_ID' => $this->id, 'Comment_Vote_Username' => $this->getUser()->getName() ], __METHOD__ ); if ( $row !== false ) { $vote = $row->Comment_Vote_Score; } else { $vote = false; } } $this->currentVote = $vote; $this->currentScore = isset( $data['total_vote'] ) ? $data['total_vote'] : $this->getScore(); } public static function newFromID( $id ) { $context = RequestContext::getMain(); $dbr = wfGetDB( DB_REPLICA ); if ( !is_numeric( $id ) || $id == 0 ) { return null; } $tables = []; $params = []; $joinConds = []; // Defaults (for non-social wikis) $tables[] = 'Comments'; $fields = [ 'Comment_Username', 'Comment_IP', 'Comment_Text', 'Comment_Date', 'Comment_Date AS timestamp', 'Comment_user_id', 'CommentID', 'Comment_Parent_ID', 'CommentID', 'Comment_Page_ID' ]; // If SocialProfile is installed, query the user_stats table too. if ( class_exists( 'UserProfile' ) && $dbr->tableExists( 'user_stats' ) ) { $tables[] = 'user_stats'; $fields[] = 'stats_total_points'; $joinConds = [ 'Comments' => [ 'LEFT JOIN', 'Comment_user_id = stats_user_id' ] ]; } // Perform the query $res = $dbr->select( $tables, $fields, [ 'CommentID' => $id ], __METHOD__, $params, $joinConds ); $row = $res->fetchObject(); if ( $row->Comment_Parent_ID == 0 ) { $thread = $row->CommentID; } else { $thread = $row->Comment_Parent_ID; } $data = [ 'Comment_Username' => $row->Comment_Username, 'Comment_IP' => $row->Comment_IP, 'Comment_Text' => $row->Comment_Text, 'Comment_Date' => $row->Comment_Date, 'Comment_user_id' => $row->Comment_user_id, 'Comment_user_points' => ( isset( $row->stats_total_points ) ? number_format( $row->stats_total_points ) : 0 ), 'CommentID' => $row->CommentID, 'Comment_Parent_ID' => $row->Comment_Parent_ID, 'thread' => $thread, 'timestamp' => wfTimestamp( TS_UNIX, $row->timestamp ) ]; $page = new CommentsPage( $row->Comment_Page_ID, $context ); return new Comment( $page, $context, $data ); } /** * Is the given User the owner (author) of this comment? * * @param User $user * @return bool */ public function isOwner( User $user ) { return ( $this->username === $user->getName() && $this->userID === $user->getId() ); } /** * Parse and return the text for this comment * * @return mixed|string * @throws MWException */ function getText() { $parser = MediaWikiServices::getInstance()->getParser(); $commentText = trim( str_replace( '"', "'", $this->text ) ); $comment_text_parts = explode( "\n", $commentText ); $comment_text_fix = ''; foreach ( $comment_text_parts as $part ) { $comment_text_fix .= ( ( $comment_text_fix ) ? "\n" : '' ) . trim( $part ); } if ( $this->getTitle()->getArticleID() > 0 ) { $commentText = $parser->recursiveTagParse( $comment_text_fix ); } else { $commentText = $this->getOutput()->parse( $comment_text_fix ); } // really bad hack because we want to parse=firstline, but don't want wrapping

tags if ( substr( $commentText, 0, 3 ) == '

' ) { $commentText = substr( $commentText, 3 ); } if ( substr( $commentText, strlen( $commentText ) - 4, 4 ) == '

' ) { $commentText = substr( $commentText, 0, strlen( $commentText ) - 4 ); } // make sure link text is not too long (will overflow) // this function changes too long links to http://www.abc....xyz.html $commentText = preg_replace_callback( "/(]*>)(.*?)(<\/a>)/i", [ 'CommentFunctions', 'cutCommentLinkText' ], $commentText ); return $commentText; } /** * Adds the comment and all necessary info into the Comments table in the * database. * * @param string $text text of the comment * @param CommentsPage $page container page * @param User $user user commenting * @param int $parentID ID of parent comment, if this is a reply * * @return Comment the added comment */ static function add( $text, CommentsPage $page, User $user, $parentID ) { $dbw = wfGetDB( DB_MASTER ); $context = RequestContext::getMain(); Wikimedia\suppressWarnings(); $commentDate = date( 'Y-m-d H:i:s' ); Wikimedia\restoreWarnings(); // ## START ## 25.05.2019 von Bernhard Linz ################################################################################################### $kok_username = preg_match('/(?<=#START#).*?(?=#ENDE#)/s', $text, $result); $kok_username = $result[0]; $text = str_replace('#START#' . $result[0] . '#ENDE#', '', $text); if ( $kok_username == "" ) { $kok_username = $user->getName(); } if ( $kok_username == "none" ) { $kok_username = $user->getName(); } // ## ENDE ## 25.05.2019 von Bernhard Linz ################################################################################################### $dbw->insert( 'Comments', [ 'Comment_Page_ID' => $page->id, // ## START ## 25.05.2019 von Bernhard Linz ################################################################################################### //'Comment_Username' => $user->getName(), 'Comment_Username' => $kok_username, // ## ENDE ## 25.05.2019 von Bernhard Linz ################################################################################################### 'Comment_user_id' => $user->getId(), 'Comment_Text' => $text, 'Comment_Date' => $commentDate, 'Comment_Parent_ID' => $parentID, 'Comment_IP' => $_SERVER['REMOTE_ADDR'] ], __METHOD__ ); $commentId = $dbw->insertId(); $id = $commentId; $page->clearCommentListCache(); // Add a log entry. self::log( 'add', $user, $page->id, $commentId, $text ); $dbr = wfGetDB( DB_REPLICA ); if ( class_exists( 'UserProfile' ) && $dbr->tableExists( 'user_stats' ) ) { $res = $dbr->select( // need this data for seeding a Comment object 'user_stats', 'stats_total_points', [ 'stats_user_id' => $user->getId() ], __METHOD__ ); $row = $res->fetchObject(); $userPoints = number_format( $row->stats_total_points ); } else { $userPoints = 0; } if ( $parentID == 0 ) { $thread = $id; } else { $thread = $parentID; } $data = [ 'Comment_Username' => $user->getName(), 'Comment_IP' => $context->getRequest()->getIP(), 'Comment_Text' => $text, 'Comment_Date' => $commentDate, 'Comment_user_id' => $user->getId(), 'Comment_user_points' => $userPoints, 'CommentID' => $id, 'Comment_Parent_ID' => $parentID, 'thread' => $thread, 'timestamp' => strtotime( $commentDate ) ]; $page = new CommentsPage( $page->id, $context ); $comment = new Comment( $page, $context, $data ); Hooks::run( 'Comment::add', [ $comment, $commentId, $comment->page->id ] ); // ## START ## 25.05.2019 von Bernhard Linz ################################################################################################### // Kommentar auch noch einmal per Email versenden (zur Kontrolle) $znilpageTitle = Title::newFromID( $comment->page->id ); $comment_mailto = "root@linz.email"; $comment_mailsubject = "Neuer Kommentar von: " . $kok_username . " - IP: " . $_SERVER['REMOTE_ADDR'] . " - DNS: " . gethostbyaddr($_SERVER['REMOTE_ADDR']) ; $comment_mailfrom = "MIME-Version: 1.0\r\n"; $comment_mailfrom .= "Content-type: text/html; charset=utf-8\r\n"; $comment_mailfrom .= "From: znil.net Kommentare \r\n"; // $comment_url = $znilpageTitle; $comment_url = "https://znil.net/index.php?title={$znilpageTitle}#comment-{$commentId}"; // $comment_url = "getFullURL() . "\">" . $title->getFullURL() . ""; $comment_mailtext = $commentDate . "

" . $comment_url . "


" . "IP: " . $_SERVER['REMOTE_ADDR'] . "
" . "DNS: " . gethostbyaddr($_SERVER['REMOTE_ADDR']) ."

" . $kok_username . "

" . $text; $comment_mailtext = nl2br($comment_mailtext); mail($comment_mailto, $comment_mailsubject, $comment_mailtext, $comment_mailfrom); // ## ENDE ## 25.05.2019 von Bernhard Linz ################################################################################################### return $comment; } /** * Gets the score for this comment from the database table Comments_Vote * * @return string */ function getScore() { $dbr = wfGetDB( DB_REPLICA ); $row = $dbr->selectRow( 'Comments_Vote', [ 'SUM(Comment_Vote_Score) AS CommentScore' ], [ 'Comment_Vote_ID' => $this->id ], __METHOD__ ); $score = '0'; if ( $row !== false && $row->CommentScore ) { $score = $row->CommentScore; } return $score; } /** * Adds a vote for a comment if the user hasn't voted for said comment yet. * * @param int $value Upvote or downvote (1 or -1) */ function vote( $value ) { $dbw = wfGetDB( DB_MASTER ); if ( $value < -1 ) { // limit to range -1 -> 0 -> 1 $value = -1; } elseif ( $value > 1 ) { $value = 1; } if ( $value == $this->currentVote ) { // user toggling off a preexisting vote $value = 0; } Wikimedia\suppressWarnings(); $commentDate = date( 'Y-m-d H:i:s' ); Wikimedia\restoreWarnings(); if ( $this->currentVote === false ) { // no vote, insert $dbw->insert( 'Comments_Vote', [ 'Comment_Vote_id' => $this->id, 'Comment_Vote_Username' => $this->getUser()->getName(), 'Comment_Vote_user_id' => $this->getUser()->getId(), 'Comment_Vote_Score' => $value, 'Comment_Vote_Date' => $commentDate, 'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR'] ], __METHOD__ ); } else { // already a vote, update $dbw->update( 'Comments_Vote', [ 'Comment_Vote_Score' => $value, 'Comment_Vote_Date' => $commentDate, 'Comment_Vote_IP' => $_SERVER['REMOTE_ADDR'] ], [ 'Comment_Vote_id' => $this->id, 'Comment_Vote_Username' => $this->getUser()->getName(), 'Comment_Vote_user_id' => $this->getUser()->getId(), ], __METHOD__ ); } $score = $this->getScore(); $this->currentVote = $value; $this->currentScore = $score; } /** * Deletes entries from Comments and Comments_Vote tables and clears caches */ function delete() { $dbw = wfGetDB( DB_MASTER ); $dbw->startAtomic( __METHOD__ ); $dbw->delete( 'Comments', [ 'CommentID' => $this->id ], __METHOD__ ); $dbw->delete( 'Comments_Vote', [ 'Comment_Vote_ID' => $this->id ], __METHOD__ ); $dbw->endAtomic( __METHOD__ ); // Log the deletion to Special:Log/comments. self::log( 'delete', $this->getUser(), $this->page->id, $this->id ); // Clear memcache & Squid cache $this->page->clearCommentListCache(); // Ping other extensions that may have hooked into this point (i.e. LinkFilter) Hooks::run( 'Comment::delete', [ $this, $this->id, $this->page->id ] ); } /** * Log an action in the comment log. * * @param string $action Action to log, can be either 'add' or 'delete' * @param User $user User who performed the action * @param int $pageId Page ID of the page that contains the comment thread * @param int $commentId Comment ID of the affected comment * @param string|null $commentText Supplementary log comment, if any */ static function log( $action, $user, $pageId, $commentId, $commentText = null ) { global $wgCommentsInRecentChanges; $logEntry = new ManualLogEntry( 'comments', $action ); $logEntry->setPerformer( $user ); $logEntry->setTarget( Title::newFromId( $pageId ) ); if ( $commentText !== null ) { $logEntry->setComment( $commentText ); } $logEntry->setParameters( [ '4::commentid' => $commentId ] ); $logId = $logEntry->insert(); $logEntry->publish( $logId, ( $wgCommentsInRecentChanges ? 'rcandudp' : 'udp' ) ); } /** * Return the HTML for the comment vote links * * @param int $voteType up (+1) vote or down (-1) vote * @return string */ function getVoteLink( $voteType ) { global $wgExtensionAssetsPath; // Blocked users cannot vote, obviously if ( $this->getUser()->isBlocked() ) { return ''; } if ( !$this->getUser()->isAllowed( 'comment' ) ) { return ''; } $voteLink = ''; if ( $this->getUser()->isLoggedIn() ) { $voteLink .= ''; } else { $login = SpecialPage::getTitleFor( 'Userlogin' ); // Anonymous users need to log in before they can vote $urlParams = []; // @todo FIXME: *when* and *why* is this null? if ( $this->page->title instanceof Title ) { $returnTo = $this->page->title->getPrefixedDBkey(); // Determine a sane returnto URL parameter $urlParams = [ 'returnto' => $returnTo ]; } $voteLink .= "getLocalURL( $urlParams ) ) . "\" rel=\"nofollow\">"; } $imagePath = $wgExtensionAssetsPath . '/Comments/resources/images'; if ( $voteType == 1 ) { if ( $this->currentVote == 1 ) { $voteLink .= "\"+\""; } else { $voteLink .= "\"+\""; } } else { if ( $this->currentVote == -1 ) { $voteLink .= "\"+\""; } else { $voteLink .= "\"+\""; } } return $voteLink; } /** * Show the HTML for this comment and ignore section * * @param array $blockList List of users the current user has blocked * @param array $anonList Map of IP addresses to names like anon#1, anon#2 * @return string HTML */ function display( $blockList, $anonList ) { if ( $this->parentID == 0 ) { $container_class = 'full'; } else { $container_class = 'reply'; } $output = ''; if ( in_array( $this->username, $blockList ) ) { $output .= $this->showIgnore( false, $container_class ); $output .= $this->showComment( true, $container_class, $blockList, $anonList ); } else { $output .= $this->showIgnore( true, $container_class ); $output .= $this->showComment( false, $container_class, $blockList, $anonList ); } return $output; } /** * Show the box for if this comment has been ignored * * @param bool $hide * @param $containerClass * @return string */ function showIgnore( $hide = false, $containerClass ) { $blockListTitle = SpecialPage::getTitleFor( 'CommentIgnoreList' ); $style = ''; if ( $hide ) { $style = " style='display:none;'"; } $output = "
\n"; $output .= wfMessage( 'comments-ignore-message' )->parse(); $output .= '' . "\n"; $output .= '
' . "\n"; return $output; } /** * Show the comment * * @param bool $hide If true, comment is returned but hidden (display:none) * @param string $containerClass * @param array $blockList * @param array $anonList * @return string */ function showComment( $hide = false, $containerClass, $blockList, $anonList ) { global $wgUserLevels, $wgExtensionAssetsPath; $style = ''; if ( $hide ) { $style = " style='display:none;'"; } $commentPosterLevel = ''; if ( $this->userID != 0 ) { $title = Title::makeTitle( NS_USER, $this->username ); $commentPoster = '' . $this->username . ''; $CommentReplyTo = $this->username; if ( $wgUserLevels && class_exists( 'UserLevel' ) ) { $user_level = new UserLevel( $this->userPoints ); $commentPosterLevel = "{$user_level->getLevelName()}"; } $user = User::newFromId( $this->userID ); $CommentReplyToGender = $user->getOption( 'gender', 'unknown' ); } else { $anonMsg = $this->msg( 'comments-anon-name' )->inContentLanguage()->plain(); // ## START ## 25.05.2019 von Bernhard Linz ################################################################################################### //Bei Anonymen Benutzern den Namen trotzdem aus der Datenbank benutzen //$commentPoster = $anonMsg . ' #' . $anonList[$this->username]; $commentPoster = $this->username; if ( filter_var($commentPoster, FILTER_VALIDATE_IP) !== false ){ // Wert ist eine IP-Adresse $commentPoster = $anonMsg . ' #' . $anonList[$this->username]; } // Name Fett drucken $commentPoster = '' . $commentPoster . ''; // ## ENDE ## 25.05.2019 von Bernhard Linz ################################################################################################### $CommentReplyTo = $anonMsg; $CommentReplyToGender = 'unknown'; // Undisclosed gender as anon user } // Comment delete button for privileged users $userObj = $this->getUser(); $dlt = ''; if ( $userObj->isAllowed( 'commentadmin' ) || // Allow users to delete their own comments if that feature is enabled in // site configuration // @see https://phabricator.wikimedia.org/T147796 $userObj->isAllowed( 'comment-delete-own' ) && $this->isOwner( $userObj ) ) { $dlt = ' | ' . '' . $this->msg( 'comments-delete-link' )->plain() . ''; } // Reply Link (does not appear on child comments) $replyRow = ''; if ( $userObj->isAllowed( 'comment' ) ) { if ( $this->parentID == 0 ) { if ( $replyRow ) { $replyRow .= wfMessage( 'pipe-separator' )->plain(); } $replyRow .= " | id}\" data-comments-safe-username=\"" . htmlspecialchars( $CommentReplyTo, ENT_QUOTES ) . "\" data-comments-user-gender=\"" . htmlspecialchars( $CommentReplyToGender ) . '">' . wfMessage( 'comments-reply' )->plain() . ''; } } if ( $this->parentID == 0 ) { $comment_class = 'f-message'; } else { $comment_class = 'r-message'; } // Display Block icon for logged in users for comments of users // that are already not in your block list $blockLink = ''; if ( $userObj->getId() != 0 && $userObj->getId() != $this->userID && !( in_array( $this->userID, $blockList ) ) ) { $blockLink = ' \"\"/ "; } // Default avatar image, if SocialProfile extension isn't enabled global $wgCommentsDefaultAvatar; // ## START ## 25.05.2019 von Bernhard Linz ################################################################################################### if ( $this->username == "BLinz" ) { $avatarImg = ''; } else { $avatarImg = ''; } // ## ENDE ## 25.05.2019 von Bernhard Linz ################################################################################################### // If SocialProfile *is* enabled, then use its wAvatar class to get the avatars for each commenter if ( class_exists( 'wAvatar' ) ) { $avatar = new wAvatar( $this->userID, 'ml' ); $avatarImg = $avatar->getAvatarURL() . "\n"; } $output = "
" . "\n"; $output .= "
{$avatarImg}
" . "\n"; $output .= '
' . "\n"; $output .= '
' . "\n"; $output .= "{$commentPoster}"; $output .= "{$commentPosterLevel} {$blockLink}" . "\n"; Wikimedia\suppressWarnings(); // E_STRICT bitches about strtotime() $output .= '
' . wfMessage( 'comments-time-ago', CommentFunctions::getTimeAgo( strtotime( $this->date ) ) )->parse() . '
' . "\n"; Wikimedia\restoreWarnings(); $output .= '
' . "\n"; $output .= $this->getScoreHTML(); $output .= '
' . "\n"; $output .= '
' . "\n"; $output .= "
" . "\n"; $output .= $this->getText(); $output .= '
' . "\n"; $output .= '
' . "\n"; if ( $this->page->title ) { // for some reason doesn't always exist $output .= 'id}\" rel=\"nofollow\">" . $this->msg( 'comments-permalink' )->plain() . ' '; } if ( $replyRow || $dlt ) { $output .= "{$replyRow} {$dlt}" . "\n"; } $output .= '
' . "\n"; $output .= '
' . "\n"; $output .= '
' . "\n"; $output .= '
' . "\n"; return $output; } /** * Get the HTML for the comment score section of the comment * * @return string */ function getScoreHTML() { $output = ''; if ( $this->page->allowMinus == true || $this->page->allowPlus == true ) { $output .= '' . wfMessage( 'comments-score-text' )->plain() . " id}\">{$this->currentScore}"; // Voting is possible only when database is unlocked if ( !wfReadOnly() ) { // You can only vote for other people's comments, not for your own if ( $this->getUser()->getName() != $this->username ) { $output .= "id}\">"; if ( $this->page->allowPlus == true ) { $output .= $this->getVoteLink( 1 ); } if ( $this->page->allowMinus == true ) { $output .= $this->getVoteLink( -1 ); } $output .= ''; } else { $output .= wfMessage( 'word-separator' )->plain() . wfMessage( 'comments-you' )->plain(); } } } return $output; } }