HEX
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.30
System: Linux iZj6c1151k3ad370bosnmsZ 3.10.0-1160.76.1.el7.x86_64 #1 SMP Wed Aug 10 16:21:17 UTC 2022 x86_64
User: root (0)
PHP: 7.4.30
Disabled: NONE
Upload Files
File: //var/www/html/phpmyfaq/src/phpMyFAQ/Stopwords.php
<?php

/**
 * The main Stopwords class.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at http://mozilla.org/MPL/2.0/.
 *
 * @package   phpMyFAQ
 * @author    Anatoliy Belsky
 * @author    Matteo Scaramuccia <matteo@phpmyfaq.de>
 * @copyright 2009-2022 phpMyFAQ Team
 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link      https://www.phpmyfaq.de
 * @since     2009-04-01
 */

namespace phpMyFAQ;

/**
 * Class Stopwords
 *
 * @package phpMyFAQ
 */
class Stopwords
{
    /**
     * @var Configuration
     */
    private $config;

    /**
     * @var string
     */
    private $language;

    /**
     * Table name.
     *
     * @var string
     */
    private $tableName;

    /**
     * Constructor.
     *
     * @param Configuration $config
     */
    public function __construct(Configuration $config)
    {
        $this->config = $config;
        $this->tableName = Database::getTablePrefix() . 'faqstopwords';
    }

    /**
     * @return string
     */
    public function getLanguage(): string
    {
        return $this->language;
    }

    /**
     * @return string
     */
    public function getTableName(): string
    {
        return $this->tableName;
    }

    /**
     * @param string $language
     */
    public function setLanguage(string $language): void
    {
        $this->language = $language;
    }

    /**
     * @param string $tableName
     */
    public function setTableName(string $tableName): void
    {
        $this->tableName = $tableName;
    }

    /**
     * Add a word to the stop words dictionary.
     * If the given word already exists, false is returned.
     *
     * @param string $word
     * @return bool
     */
    public function add(string $word): bool
    {
        if (!$this->match($word)) {
            $sql = sprintf(
                "INSERT INTO %s VALUES(%d, '%s', '%s')",
                $this->tableName,
                $this->config->getDb()->nextId($this->tableName, 'id'),
                $this->language,
                $word
            );
            $this->config->getDb()->query($sql);

            return true;
        }

        return false;
    }

    /**
     * Update a word in the stop words dictionary.
     *
     * @param int    $id
     * @param string $word
     * @return bool
     */
    public function update(int $id, string $word): bool
    {
        $sql = "UPDATE %s SET stopword = '%s' WHERE id = %d AND lang = '%s'";
        $sql = sprintf(
            $sql,
            $this->tableName,
            $word,
            $id,
            $this->language
        );

        return (bool) $this->config->getDb()->query($sql);
    }

    /**
     * Remove a word from the stop word dictionary.
     *
     * @param int $id
     * @return bool
     */
    public function remove(int $id): bool
    {
        $sql = sprintf(
            "DELETE FROM %s WHERE id = %d AND lang = '%s'",
            $this->tableName,
            $id,
            $this->language
        );

        return (bool) $this->config->getDb()->query($sql);
    }

    /**
     * Match a word against the stop words dictionary.
     *
     * @param string $word
     * @return bool
     */
    public function match(string $word): bool
    {
        $sql = sprintf(
            "SELECT id FROM %s WHERE LOWER(stopword) = LOWER('%s') AND lang = '%s'",
            $this->tableName,
            $word,
            $this->language
        );

        $result = $this->config->getDb()->query($sql);

        return $this->config->getDb()->numRows($result) > 0;
    }

    /**
     * Retrieve all the stop words by a certain language.
     *
     * @param string $lang      Language to retrieve stop words by
     * @param bool   $wordsOnly
     *
     * @return string[]
     */
    public function getByLang($lang = null, $wordsOnly = false): array
    {
        $lang = is_null($lang) ? $this->config->getLanguage()->getLanguage() : $lang;
        $sql = sprintf(
            "SELECT id, lang, LOWER(stopword) AS stopword FROM %s WHERE lang = '%s'",
            $this->tableName,
            $lang
        );

        $result = $this->config->getDb()->query($sql);

        $stopWords = [];

        if ($wordsOnly) {
            while (($row = $this->config->getDb()->fetchObject($result)) == true) {
                $stopWords[] = $row->stopword;
            }
        } else {
            return $this->config->getDb()->fetchAll($result);
        }

        return $stopWords;
    }

    /**
     * Filter some text cutting out all non words and stop words.
     *
     * @param string $input text to filter
     * @return string[]
     */
    public function clean(string $input): array
    {
        $words = explode(' ', $input);
        $stop_words = $this->getByLang(null, true);
        $retval = [];

        foreach ($words as $word) {
            $word = Strings::strtolower($word);
            if (
                !is_numeric($word) && 1 < Strings::strlen($word)
                && !in_array($word, $stop_words) && !in_array($word, $retval)
            ) {
                $retval[] = $word;
            }
        }

        return $retval;
    }

    /**
     * This function checks the content against a bad word list if the banned
     * word spam protection has been activated from the general phpMyFAQ
     * configuration.
     *
     * @param string $content
     * @return bool
     */
    public function checkBannedWord(string $content): bool
    {
        // Sanity checks
        $content = Strings::strtolower(trim($content));
        if (('' === $content) || (!$this->config->get('spam.checkBannedWords'))) {
            return true;
        }

        // Check if we check more than one word
        $checkWords = explode(' ', $content);
        if (1 === count($checkWords)) {
            $checkWords = [$content];
        }

        $bannedWords = $this->getBannedWords();
        // We just search a match of, at least, one banned word into $content
        if (is_array($bannedWords)) {
            foreach ($bannedWords as $bannedWord) {
                foreach ($checkWords as $word) {
                    if (Strings::strtolower($word) === Strings::strtolower($bannedWord)) {
                        return false;
                    }
                }
            }
        }

        return true;
    }

    /**
     * This function returns the banned words dictionary as an array.
     *
     * @return string[]
     */
    private function getBannedWords(): array
    {
        $bannedTrimmedWords = [];
        $bannedWordsFile = PMF_SRC_DIR . '/blockedwords.txt';
        $bannedWords = [];

        // Read the dictionary
        if (file_exists($bannedWordsFile) && is_readable($bannedWordsFile)) {
            $bannedWords = file_get_contents($bannedWordsFile);
        }

        // Trim it
        foreach (explode("\n", $bannedWords) as $word) {
            $bannedTrimmedWords[] = trim($word);
        }

        return $bannedTrimmedWords;
    }
}