HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/proundcontra.mosmuc.de/statisticsMgr.php
<?php
class StatisticsMgr
{
    public function __construct()
    {
        $this->queryCacheHits   = 0;
        $this->queryCacheMisses = 0;

        $this->run();
    }

    /*
     * run all necessary statistics
     */
    public function run()
    {
        // Currently empty, but here for future expansion
    }

    public function queryCacheHit()
    {
        $this->queryCacheHits++;
    }

    public function queryCacheMiss()
    {
        $this->queryCacheMisses++;
    }

    public function queryCacheHits()
    {
        return $this->queryCacheHits;
    }

    public function queryCacheMisses()
    {
        return $this->queryCacheMisses;
    }

    public function updateQuestionStats($questionId)
    {
        global $sDB, $sTimer;

        error_log("update question stats for question $questionId");
        $sTimer->start("updateQuestionStats");

        $res = $sDB->exec("
            SELECT *
            FROM `questions`
            WHERE `questionId` = '".i($questionId)."'
            LIMIT 1;
        ");
        if (!mysqli_num_rows($res)) {
            return false;
        }
        $q = mysqli_fetch_object($res);

        $this->updateQuestionScore($questionId);
        $this->updateArgumentScoreBatch($questionId);

        $sTimer->stop("updateQuestionStats");
    }

    private function trendingScore($score, $dateAdded)
    {
        $timePassed = $dateAdded - 1338501600;
        $s          = 0;

        if ($score > 0) {
            $s = 1;
        } else if ($score < 0) {
            $s = -1;
        }

        $ret = round(log(max(abs($score), 1), 10) + $s * $timePassed / 45000);
        return $ret;
    }

    private function updateQuestionScore($questionId)
    {
        global $sDB, $sTimer;

        $sTimer->start("updateQuestionScore");

        $res = $sDB->exec("
            SELECT *
            FROM `questions`
            WHERE `questionId` = '".i($questionId)."'
            LIMIT 1;
        ");
        if (!mysqli_num_rows($res)) {
            return false;
        }
        $q = mysqli_fetch_object($res);

        $num = [
            VOTE_UP => 0,
            VOTE_DN => 0
        ];
        $res = $sDB->exec("
            SELECT count(*) as `cnt`, `vote`
            FROM `user_votes`
            WHERE `questionId` = '".i($questionId)."'
              AND `argumentId` = '0'
            GROUP BY `vote`;
        ");
        while ($row = mysqli_fetch_object($res)) {
            $num[$row->vote] = $row->cnt;
        }

        $score         = $num[VOTE_UP] - $num[VOTE_DN];
        $scoreTop      = $score;
        $scoreTrending = $this->trendingScore($score, $q->dateAdded);

        $oldScore = $q->score;
        error_log("update question score for $questionId: $oldScore -> $score");

        $sDB->exec("
            UPDATE `questions`
            SET `score`         = '".i($score)."',
                `scoreTrending` = '".i($scoreTrending)."',
                `scoreTop`      = '".i($scoreTop)."'
            WHERE `questionId`  = '".i($questionId)."'
            LIMIT 1;
        ");

        $sTimer->stop("updateQuestionScore");
    }

    /*
     * batch update argument scores for all arguments of the given question.
     */
    private function updateArgumentScoreBatch($questionId)
    {
        global $sDB, $sTimer;

        $sTimer->start("updateArgumentScoreBatch");
        $sTimer->start("updateArgumentScoreBatch::Fetch");

        $score = [];

        $res = $sDB->exec("
            SELECT count(*) as `cnt`, `vote`, `argumentId`
            FROM `user_votes`
            WHERE `questionId` = '".i($questionId)."'
            GROUP BY `argumentId`, `vote`;
        ");
        while ($row = mysqli_fetch_object($res)) {
            if ($row->argumentId == 0) {
                continue;
            }
            if (!isset($score[$row->argumentId])) {
                $score[$row->argumentId] = 0;
            }

            // The 'vote' field is presumably 1 or -1, multiplied by the count
            $score[$row->argumentId] += $row->vote * $row->cnt;
        }

        $sTimer->stop("updateArgumentScoreBatch::Fetch");
        $sTimer->start("updateArgumentScoreBatch::Update");

        $sDB->exec("START TRANSACTION;");
        foreach ($score as $k => $v) {
            $sDB->exec("
                UPDATE `arguments`
                SET `score` = '".i($v)."'
                WHERE `questionId` = '".i($questionId)."'
                  AND `argumentId` = '".i($k)."'
                LIMIT 1;
            ");
        }
        $sDB->exec("COMMIT;");

        $sTimer->stop("updateArgumentScoreBatch::Update");
        $sTimer->stop("updateArgumentScoreBatch");
    }

    private function updateArgumentScore($questionId, $argumentId)
    {
        global $sDB, $sTimer;

        $num = [
            VOTE_UP => 0,
            VOTE_DN => 0
        ];

        $res = $sDB->exec("
            SELECT count(*) as `cnt`, `vote`
            FROM `user_votes`
            WHERE `questionId` = '".i($questionId)."'
              AND `argumentId` = '".i($argumentId)."'
            GROUP BY `vote`;
        ");
        while ($row = mysqli_fetch_object($res)) {
            $num[$row->vote] = $row->cnt;
        }

        $score = $num[VOTE_UP] - $num[VOTE_DN];

        $sDB->exec("
            UPDATE `arguments`
            SET `score` = '".i($score)."'
            WHERE `questionId` = '".i($questionId)."'
              AND `argumentId` = '".i($argumentId)."'
            LIMIT 1;
        ");
    }

    /*
     * Remove all votes from this argument.
     */
    public function resetArgumentVotes(Argument $argument)
    {
        global $sDB;

        $inc = 0;

        $res = $sDB->exec("
            SELECT *
            FROM `user_votes`
            WHERE `argumentId` = '".i($argument->argumentId())."';
        ");
        while ($row = mysqli_fetch_object($res)) {
            $inc += $row->vote;
        }

        $sDB->execUsers("
            UPDATE `users`
            SET `scoreArguments` = `scoreArguments` - ".i($inc)."
            WHERE `userId` = '".i($argument->userId())."'
            LIMIT 1;
        ");

        $sDB->exec("
            DELETE FROM `user_votes`
            WHERE `argumentId` = '".i($argument->argumentId())."';
        ");
    }

    /*
     * Remove all votes from this question.
     * Make sure that no arguments exist before this call!
     */
    public function resetQuestionVotes(Question $question)
    {
        global $sDB;

        $inc = 0;

        $res = $sDB->exec("
            SELECT *
            FROM `user_votes`
            WHERE `questionId` = '".i($question->questionId())."';
        ");
        while ($row = mysqli_fetch_object($res)) {
            $inc += $row->vote;
        }

        $sDB->execUsers("
            UPDATE `users`
            SET `scoreQuestions` = `scoreQuestions` - ".i($inc)."
            WHERE `userId` = '".i($question->authorId())."'
            LIMIT 1;
        ");

        $sDB->exec("
            DELETE FROM `user_votes`
            WHERE `questionId` = '".i($question->questionId())."';
        ");
    }

    public function vote(Question $question, $argumentId, $vote, $user = false, $forceVote = false)
    {
        global $sUser, $sDB, $sQuery, $sPermissions;

        $questionId = $question->questionId();

        if (!$user) {
            $user = $sUser;
            if (!$sUser->isLoggedIn() && $question->type() != QUESTION_TYPE_UNLISTED) {
                return false;
            }
        }

        if (!in_array($vote, [VOTE_UP, VOTE_DN, VOTE_NONE])) {
            return false;
        }

        if ($sPermissions->getPermission($user, ACTION_VOTE) == PERMISSION_DISALLOWED) {
            return false;
        }

        if (!$user->isLoggedIn()) {
            return false;
        }

        $this->lazyUpdateUserStats($questionId, $argumentId, $vote, $user->getUserId());

        $sDB->exec("
            DELETE FROM `user_votes`
            WHERE `userId` = '".i($user->getUserId())."'
              AND `questionId` = '".i($questionId)."'
              AND `argumentId` = '".i($argumentId)."';
        ");

        if ($vote != VOTE_NONE) {
            $sDB->exec("
                INSERT INTO `user_votes`
                    (`voteId`, `userId`, `questionId`, `argumentId`, `vote`, `dateAdded`)
                VALUES
                    (NULL,
                     '".i($user->getUserId())."',
                     '".i($questionId)."',
                     '".i($argumentId)."',
                     '".i($vote)."',
                     '".time()."');
            ");
        }

        if ($argumentId) {
            $this->updateArgumentScore($questionId, $argumentId);
        } else {
            $this->updateQuestionStats($questionId);
        }

        return true;
    }

    /*
     * Update user score lazily.
     * After this call, user stats are updated such that the vote of userId is taken into account.
     */
    private function lazyUpdateUserStats($questionId, $argumentId, $vote, $userId)
    {
        global $sUser, $sDB, $sQuery;

        if ($sUser->getUserId() == 0) {
            return;
        }

        $res = $sDB->exec("
            SELECT *
            FROM `user_votes`
            WHERE `userId` = '".i($sUser->getUserId())."'
              AND `questionId` = '".i($questionId)."'
              AND `argumentId` = '".i($argumentId)."';
        ");

        $inc = $vote;
        while ($row = mysqli_fetch_object($res)) {
            $inc -= $row->vote;
        }

        $authorId = $sQuery->getAuthorById($questionId, $argumentId);

        if ($argumentId) {
            $sDB->execUsers("
                UPDATE `users`
                SET `scoreArguments` = `scoreArguments` + ".i($inc)."
                WHERE `userId` = '".i($authorId)."'
                LIMIT 1;
            ");
        } else {
            $sDB->execUsers("
                UPDATE `users`
                SET `scoreQuestions` = `scoreQuestions` + ".i($inc)."
                WHERE `userId` = '".i($authorId)."'
                LIMIT 1;
            ");
        }
    }

    private $queryCacheHits;
    private $queryCacheMisses;
}
?>