Your IP : 216.73.216.240


Current Path : /home/j/u/v/juvelize/martine/components/com_easybookreloaded/models/
Upload File :
Current File : /home/j/u/v/juvelize/martine/components/com_easybookreloaded/models/entry.php

<?php

/**
 * @copyright
 * @package    Easybook Reloaded - EBR for Joomla! 3.x
 * @author     Viktor Vogel <admin@kubik-rubik.de>
 * @version    3.4.1.1-FREE - 2021-08-29
 * @link       https://kubik-rubik.de/ebr-easybook-reloaded
 *
 * @license    GNU/GPL
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
defined('_JEXEC') || die('Restricted access');

use EasybookReloaded\{Helper, Content, Route};
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\{Factory, Language\Text, Uri\Uri, Mail\MailHelper};
use Joomla\Input\Input;

/**
 * Class EasybookReloadedModelEntry
 *
 * @since   3.4.0-FREE
 * @version 3.4.1.1-FREE
 */
class EasybookReloadedModelEntry extends BaseDatabaseModel
{
    /**
     * @var object $data
     * @since 3.4.0-FREE
     */
    protected $data;

    /**
     * @var int|string $id
     * @since 3.4.0-FREE
     */
    protected $id;

    /**
     * @var array $badWords
     * @since 3.4.0-FREE
     */
    protected $badWords;

    /**
     * @var object $input
     * @since 3.4.0-FREE
     */
    protected $input;

    /**
     * @var object $user
     * @since 3.4.0-FREE
     */
    protected $user;

    /**
     * @var object $session
     * @since 3.4.0-FREE
     */
    protected $session;

    /**
     * @var object $app
     * @since 3.4.0-FREE
     */
    protected $app;

    /**
     * EasybookReloadedModelEntry constructor.
     *
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function __construct()
    {
        parent::__construct();

        $this->app = Factory::getApplication();
        $this->user = Factory::getUser();
        $this->session = Factory::getSession();
        $this->input = new Input();

        $this->id = $this->input->getInt('cid', 0);

        // Requests from the notification mail do send a valid hash value
        if ($hashRequest = $this->input->getString('hash')) {
            $hashData = explode('-', $hashRequest);

            if (count($hashData) !== 2) {
                return;
            }

            if (!empty($hashData[0]) && is_numeric($hashData[0])) {
                $this->id = $hashData[0];
            }
        }
    }

    /**
     * Stores the guestbook entries into the database
     *
     * @return bool|JTable
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function store()
    {
        $row = $this->getTable('entry', 'EasybookReloadedTable');

        // Load all request variables
        $data = $this->input->request->getArray();
        array_walk(
            $data,
            static function (&$data) {
                $data = htmlspecialchars(strip_tags(trim($data)));
            }
        );

        // Get unfiltered request variable for gbtext
        $data['gbtext'] = htmlspecialchars($this->input->getRaw('gbtext'), ENT_QUOTES);

        $date = Factory::getDate();

        if ($this->user->guest === 0 && !EASYBOOK_CANEDIT) {
            $data['gbname'] = $this->user->get('username');

            if (Helper::getParams('registeredUsername')) {
                $data['gbname'] = $this->user->get('name');
            }

            $data['gbmail'] = $this->user->get('email');
        }

        if (!isset($data['id'])) {
            $data['gbdate'] = $date->toSql();
            $data['published'] = Helper::getParams('defaultPublished', 1);
            $data['gbip'] = '0.0.0.0';

            if (Helper::getParams('enableLog', true)) {
                $data['gbip'] = Content::getIpAddress();
            }

            $data['gbcomment'] = null;
        }

        $data['gbimage'] = '';
        $data['gbimageUpload'] = '';

        // Validate the entered data
        if (!$this->validate($data)) {
            return false;
        }

        if (!$row->save($data)) {
            throw new Exception(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 404);
        }

        $this->clearSession();

        return $row;
    }

    /**
     * Validates all entered data that was submitted by the user
     *
     * @param $data
     *
     * @return bool
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    private function validate(&$data): bool
    {
        $errors = [];
        $error = false;

        $gbId = Route::getGbId();
        $this->session->clear('gbid', 'easybookreloaded');

        if (!empty($gbId)) {
            if ((int)$data['gbid'] !== $gbId) {
                unset($data['gbid']);
                $error = true;
                $errors['gbid'] = true;
            }
        } else {
            // No chance, my little friend :-)
            unset($data['gbid']);
            $error = true;
            $errors['gbid'] = true;
        }

        if ($this->user->guest || Helper::getParams('enableSpamCheckRegistered')) {
            $time = $this->session->get('time', null, 'easybookreloaded');

            if ($time === '') {
                $error = true;
                $errors['sessionVariable'] = true;
            } elseif ((time() - Helper::getParams('typeTimeSeconds')) <= $time) {
                $error = true;
                $errors['spamCheckResult'] = true;
            }

            if (Helper::getParams('enableSpamCheck', true)) {
                $spamcheck1 = $this->session->get('spamcheck1', false, 'easybookreloaded');
                $spamcheck2 = $this->session->get('spamcheck2', false, 'easybookreloaded');
                $spamcheckResult = $this->session->get('spamCheckResult', null, 'easybookreloaded');
                $spamCheckFieldName = $this->session->get('spamCheckFieldName', false, 'easybookreloaded');

                if ((empty($spamcheck1)) || (empty($spamcheck2)) || ($spamcheckResult === null) || (empty($spamCheckFieldName))) {
                    $error = true;
                    $errors['sessionVariable'] = true;
                } elseif ($data[$spamCheckFieldName] === '' || (int)$data[$spamCheckFieldName] !== $spamcheckResult) {
                    $error = true;
                    $errors['easycalccheck'] = true;
                }
            }

            if (Helper::getParams('spamCheckQuestion') && (Helper::getParams('spamCheckQuestionQuestion') && Helper::getParams('spamCheckQuestionAnswer'))) {
                $spamcheckQuestionFieldName = $this->session->get('spamCheckQuestionFieldName', null, 'easybookreloaded');

                if ($spamcheckQuestionFieldName === '') {
                    $error = true;
                    $errors['sessionVariable'] = true;
                } else {
                    $spamcheckQuestionAnswer = Text::_(Helper::getParams('spamCheckQuestionAnswer'));

                    if (strtolower($data[$spamcheckQuestionFieldName]) !== strtolower($spamcheckQuestionAnswer)) {
                        $error = true;
                        $errors['easycalccheckQuestion'] = true;
                    }
                }
            }

            // Akismet - Further information: http://akismet.com/
            if (Helper::getParams('akismet')) {
                $akismetKey = Helper::getParams('akismetKey');

                if ($akismetKey) {
                    $akismetUrl = Uri::getInstance()->toString();

                    $name = $data['gbname'];
                    $email = $data['gbmail'];
                    $comment = $data['gbtext'];

                    // Add title if provided
                    if (!empty($data['gbtitle'])) {
                        $comment = $data['gbtitle'] . ' ' . $comment;
                    }

                    // Check homepage if provided
                    $url = '';

                    if (!empty($data['gbpage'])) {
                        $url = $data['gbpage'];
                    }

                    $akismet = new Akismet($akismetUrl, $akismetKey);
                    $akismet->setCommentAuthor($name);
                    $akismet->setCommentAuthorEmail($email);
                    $akismet->setCommentAuthorURL($url);
                    $akismet->setCommentContent($comment);

                    if ($akismet->isCommentSpam()) {
                        $error = true;
                        $errors['akismet'] = true;
                    }
                }
            }
        }

        if (Helper::getParams('blockIp')) {
            $gbIp = Content::getIpAddress();
            $ips = array_map('trim', explode(',', Helper::getParams('blockIp')));

            foreach ($ips as $ip) {
                $ipRegexp = str_replace('x', '..?.?', preg_quote($ip, '@'));

                if (preg_match('@' . $ipRegexp . '@', $gbIp)) {
                    $error = true;
                    $errors['easycalccheck'] = true;
                }
            }
        }

        if (Helper::getParams('timeLockIp') && Helper::getParams('enableLog')) {
            $gbIp = Content::getIpAddress();
            $dateLastEntry = $this->lastEntryDate($gbIp);

            if (!empty($dateLastEntry)) {
                date_default_timezone_set('UTC');
                $dateBack = strftime("%Y-%m-%d %H:%M:%S", time() - Helper::getParams('timeLockIp'));

                if ($dateLastEntry > $dateBack) {
                    $error = true;
                    $errors['iptimelock'] = true;
                }
            }
        }

        if (empty($data['gbname'])) {
            $error = true;
            $errors['name'] = true;
        }

        if (empty($data['gbtext'])) {
            $error = true;
            $errors['text'] = true;
        } else {
            if (preg_match_all('@\[img\].+\[/img\]@isU', $data['gbtext'], $matches)) {
                $text = $data['gbtext'];

                foreach ($matches[0] as $value) {
                    $img = str_replace(['\'', "\""], '', $value);

                    if (strpos($img, ' ') === true) {
                        $imgNew = substr($img, 0, strpos($img, ' ')) . '[/img]';
                        $text = str_replace($value, $imgNew, $text);
                    }
                }

                $data['gbtext'] = $text;
            }

            if (preg_match_all('@https?://(www\.)?([a-zA-Z0-9-]+\.)?([a-zA-Z0-9-]{3,65})(\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))@is', $data['gbtext'], $matches) && count($matches[0]) > Helper::getParams('maxNumberLinks')) {
                $error = true;
                $errors['tooManyLinks'] = true;
            }

            if (preg_match('@\[link.*\].*\[/link\]@isU', $data['gbtext'])) {
                $error = true;
                $errors['easycalccheck'] = true;
            }
        }

        if (!empty($data['gbicq'])) {
            $allowed = '@^[0-9]+$@';

            if (!preg_match($allowed, $data['gbicq'])) {
                $error = true;
                $errors['icq'] = true;
            }
        }

        if (!empty($data['gbskype'])) {
            $allowed = '@^[A-Za-z0-9_\.-]+$@';

            if (!preg_match($allowed, $data['gbskype'])) {
                $error = true;
                $errors['skype'] = true;
            }
        }

        if (!empty($data['gbpage'])) {
            $data['gbpage'] = str_replace(['\'', "\""], '', $data['gbpage']);

            if (strpos($data['gbpage'], ' ') === true) {
                $data['gbpage'] = substr($data['gbpage'], 0, strpos($data['gbpage'], ' '));
            }

            // Add scheme if not provided
            if (!preg_match('@^https?://@i', $data['gbpage'])) {
                $data['gbpage'] = 'http://' . $data['gbpage'];
            }

            $data['gbpage'] = htmlspecialchars($data['gbpage'], ENT_QUOTES);
        }

        if ((!empty($data['gbmail']) || Helper::getParams('requireMail', true)) && !MailHelper::isEmailAddress($data['gbmail'])) {
            $error = true;
            $errors['mail'] = true;
        }

        if ((Helper::getParams('showTitle', true)) && (empty($data['gbtitle']) && Helper::getParams('requireTitle', true))) {
            $error = true;
            $errors['title'] = true;
        } elseif (!empty($data['gbtitle'])) {
            $data['gbtitle'] = htmlspecialchars($data['gbtitle'], ENT_QUOTES);
        }

        if (Helper::getParams('badwordfilter', true)) {
            $badWords = $this->getBadWordList();
            $badWordFilterRegexp = Helper::getParams('badwordFilterRegex', false);

            if (!empty($badWordFilterRegexp)) {
                foreach ($badWords as $badWord) {
                    $data['gbtext'] = preg_replace('@' . $badWord . '@iU', '***', $data['gbtext']);

                    if (!empty($data['gbtitle'])) {
                        $data['gbtitle'] = preg_replace('@' . $badWord . '@iU', '***', $data['gbtitle']);
                    }
                }
            } else {
                $data['gbtext'] = str_replace($badWords, '***', $data['gbtext']);

                if (!empty($data['gbtitle'])) {
                    $data['gbtitle'] = str_replace($badWords, '***', $data['gbtitle']);
                }
            }
        }

        if (empty($data['eugdpr']) && Helper::getParams('eugdpr', true)) {
            $error = true;
            $errors['eugdpr'] = true;
        }

        if ($error) {
            $this->session->set('errors', $errors, 'easybookreloaded');
            $this->app->setUserState('ebValidationErrors', $errors);
            $this->app->setUserState('ebValidationData', $data);

            return false;
        }

        return true;
    }

    /**
     * Checks the latest date of an entry from a specific IP address
     *
     * @param string $ip
     *
     * @return mixed
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    private function lastEntryDate(string $ip)
    {
        $query = "SELECT " . $this->_db->quoteName('gbdate') . " FROM " . $this->_db->quoteName('#__easybook') . " WHERE " . $this->_db->quoteName('gbip') . " = " . $this->_db->quote($ip) . " ORDER BY gbdate DESC";
        $this->_db->setQuery($query);

        return $this->_db->loadResult();
    }

    /**
     * Loads all language bad words from the database for the validation check
     *
     * @return mixed
     * @since 3.4.0-FREE
     */
    private function getBadWordList()
    {
        if (empty($this->badWords)) {
            $query = "SELECT " . $this->_db->quoteName('word') . " FROM " . $this->_db->quoteName('#__easybook_badwords') . " ORDER BY length(word) DESC";
            $this->_db->setQuery($query);
            $this->badWords = $this->_db->loadColumn();
        }

        return $this->badWords;
    }

    /**
     * Clears saved session data if entry was stored successfully in the database
     *
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    private function clearSession(): void
    {
        $this->session->clear('spamcheck1', 'easybookreloaded');
        $this->session->clear('spamcheck2', 'easybookreloaded');
        $this->session->clear('spamCheckResult', 'easybookreloaded');
        $this->session->clear('spamCheckFieldName', 'easybookreloaded');
        $this->session->clear('operator', 'easybookreloaded');
        $this->session->clear('time', 'easybookreloaded');
        $this->session->clear('spamCheckQuestionFieldName', 'easybookreloaded');
    }

    /**
     * Deletes an entry using the Table class
     *
     * @return bool
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function delete(): bool
    {
        $row = $this->getTable('entry', 'EasybookReloadedTable');

        if (!$row->delete($this->id)) {
            throw new Exception(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 404);
        }

        return true;
    }

    /**
     * Changes the status of an entry - online / offline
     *
     * @return int
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function publish(): int
    {
        $data = $this->getData();
        $status = (int)!$data->published;

        $query = "UPDATE " . $this->_db->quoteName('#__easybook') . " SET " . $this->_db->quoteName('published') . " = " . $this->_db->quote($status) . " WHERE " . $this->_db->quoteName('id') . " = " . $this->_db->quote($this->id) . " LIMIT 1;";
        $this->_db->setQuery($query);

        if (!$this->_db->execute()) {
            return -1;
        }

        return $status;
    }

    /**
     * Loads the entry data when a form is loaded
     *
     * @return JTable|mixed
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function getData()
    {
        // Error occurred - load the form with entered data again
        if ($this->input->get('retry') === 'true') {
            $this->data = $this->getTable('entry', 'EasybookReloadedTable');
            $this->data->bind($this->app->getUserState('ebValidationData'));
        }

        // Modification process of an existing entry
        if (empty($this->data) && !empty($this->id)) {
            $query = "SELECT * FROM " . $this->_db->quoteName('#__easybook') . " WHERE " . $this->_db->quoteName('id') . " = " . $this->_db->quote($this->id);
            $this->_db->setQuery($query);
            $this->data = $this->_db->loadObject();
        }

        if (!empty($this->data)) {
            $this->session->set('gbid', $this->data->gbid, 'easybookreloaded');

            return $this->data;
        }

        // First loading of the form - new entry
        $this->data = $this->getTable('entry', 'EasybookReloadedTable');
        $this->data->id = 0;

        if ($this->user->get('id')) {
            if (Helper::getParams('registeredUsername')) {
                $this->data->gbname = $this->user->get('name');
            } else {
                $this->data->gbname = $this->user->get('username');
            }

            $this->data->gbmail = $this->user->get('email');
        }

        // Okay, if we get here, then the gbid must be set. If not, then we have a direct call.
        $gbId = Route::getGbId();

        if (empty($gbId)) {
            $this->session->set('gbid', 0, 'easybookreloaded');
        }

        return $this->data;
    }

    /**
     * Creates math exercise and saves values to the session for the validation process
     *
     * @throws Exception
     * @version 3.4.1.0-FREE
     * @since   3.4.0-FREE
     */
    public function getCalcCheck(): void
    {
        if ($this->user->guest || Helper::getParams('enableSpamCheckRegistered')) {
            $this->session->set('time', time(), 'easybookreloaded');

            if (Helper::getParams('enableSpamCheck', true)) {
                $spamcheck1 = random_int(1, Helper::getParams('maxValue', 20));
                $spamcheck2 = random_int(1, Helper::getParams('maxValue', 20));
                $spamcheckResult = $spamcheck1 + $spamcheck2;
                $operatorOutput = '+';
                $operator = random_int(0, 1);

                if (Helper::getParams('operator') === 1 || (Helper::getParams('operator') === 2 && $operator === 1)) {
                    $spamcheckResult = $spamcheck1 - $spamcheck2;
                    $operatorOutput = '-';
                }

                $spamCheckFieldName = $this->getRandomValue();

                $this->session->set('spamcheck1', $spamcheck1, 'easybookreloaded');
                $this->session->set('spamcheck2', $spamcheck2, 'easybookreloaded');
                $this->session->set('spamCheckResult', $spamcheckResult, 'easybookreloaded');
                $this->session->set('spamCheckFieldName', $spamCheckFieldName, 'easybookreloaded');
                $this->session->set('operator', $operatorOutput, 'easybookreloaded');
            }

            if (Helper::getParams('spamCheckQuestion') && (Helper::getParams('spamCheckQuestionQuestion') && Helper::getParams('spamCheckQuestionAnswer'))) {
                $spamcheckQuestionFieldName = $this->getRandomValue();
                $this->session->set('spamCheckQuestionFieldName', $spamcheckQuestionFieldName, 'easybookreloaded');
            }
        }
    }

    /**
     * Creates a random string for the calc check field ID
     *
     * @return string
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    private function getRandomValue(): string
    {
        $randomString = '';

        // first character has to be a letter
        $characters = range('a', 'z');
        $randomString .= $characters[random_int(0, 25)];

        // other characters arbitrarily
        $numbers = range(0, 9);
        $characters = array_merge($characters, $numbers);

        $stringLength = random_int(4, 12);

        for ($i = 0; $i < $stringLength; $i++) {
            $randomString .= $characters[random_int(0, 35)];
        }

        return $randomString;
    }

    /**
     * Saves the comment from authorized users with admin rights for the component
     *
     * @return int
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.1-FREE
     */
    public function saveComment(): int
    {
        $row = $this->getTable('entry', 'EasybookReloadedTable');

        // Load all request variables
        $data = $this->input->request->getArray();
        array_walk(
            $data,
            static function (&$data) {
                $data = htmlspecialchars(strip_tags(trim($data)));
            }
        );

        // Get unfiltered request variable for gbtext
        $data['gbcomment'] = htmlspecialchars($this->input->getRaw('gbcomment'), ENT_QUOTES);

        $gbId = Route::getGbId();
        $this->session->clear('gbid', 'easybookreloaded');

        if (empty($gbId)) {
            return 0;
        }

        if ((int)$data['gbid'] !== $gbId) {
            return 0;
        }

        if (!$row->save($data)) {
            throw new Exception(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 404);
        }

        return $data['id'] ?? 0;
    }

    /**
     * Loads entry data from the database using JTable
     *
     * @param int $id
     *
     * @return object
     * @throws Exception
     * @since   3.4.0-FREE
     * @version 3.4.1.0-FREE
     */
    public function getRow(int $id): object
    {
        $table = $this->getTable('entry', 'EasybookReloadedTable');
        $table->load($id);

        return $table;
    }
}