shell bypass 403
<?php /** * @package Joomla.Administrator * @subpackage com_guidedtours * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Guidedtours\Administrator\Model; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\AdminModel; use Joomla\CMS\Object\CMSObject; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\ParameterType; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model class for tour * * @since 4.3.0 */ class TourModel extends AdminModel { /** * The prefix to use with controller messages. * * @var string * @since 4.3.0 */ protected $text_prefix = 'COM_GUIDEDTOURS'; /** * Type alias for content type * * @var string * @since 4.3.0 */ public $typeAlias = 'com_guidedtours.tour'; /** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success. * * @since 4.3.0 */ public function save($data) { $input = Factory::getApplication()->getInput(); // Language keys must include GUIDEDTOUR to prevent save issues if (strpos($data['description'], 'GUIDEDTOUR') !== false) { $data['description'] = strip_tags($data['description']); } if ($input->get('task') == 'save2copy') { $origTable = clone $this->getTable(); $origTable->load($input->getInt('id')); $data['published'] = 0; } // Set step language to parent tour language on save. $id = $data['id']; $lang = $data['language']; $this->setStepsLanguage($id, $lang); return parent::save($data); } /** * Prepare and sanitise the table prior to saving. * * @param \Joomla\CMS\Table\Table $table The Table object * * @return void * * @since 4.3.0 */ protected function prepareTable($table) { $date = Factory::getDate()->toSql(); $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES); if (empty($table->id)) { // Set the values $table->created = $date; // Set ordering to the last item if not set if (empty($table->ordering)) { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('MAX(ordering)') ->from($db->quoteName('#__guidedtours')); $db->setQuery($query); $max = $db->loadResult(); $table->ordering = $max + 1; } } else { // Set the values $table->modified = $date; $table->modified_by = $this->getCurrentUser()->id; } } /** * Abstract method for getting the form from the model. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return \JForm|boolean A JForm object on success, false on failure * * @since 4.3.0 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm( 'com_guidedtours.tour', 'tour', [ 'control' => 'jform', 'load_data' => $loadData, ] ); if (empty($form)) { return false; } $id = $data['id'] ?? $form->getValue('id'); $item = $this->getItem($id); // Modify the form based on access controls. if (!$this->canEditState((object) $item)) { $form->setFieldAttribute('published', 'disabled', 'true'); $form->setFieldAttribute('published', 'required', 'false'); $form->setFieldAttribute('published', 'filter', 'unset'); } $currentDate = Factory::getDate()->toSql(); $form->setFieldAttribute('created', 'default', $currentDate); $form->setFieldAttribute('modified', 'default', $currentDate); return $form; } /** * Method to get the data that should be injected in the form. * * @return mixed The data for the form. * * @since 4.3.0 */ protected function loadFormData() { // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState( 'com_guidedtours.edit.tour.data', [] ); if (empty($data)) { $data = $this->getItem(); } return $data; } /** * Method to get a single record. * * @param integer $pk The id of the primary key. * * @return CMSObject|boolean Object on success, false on failure. * * @since 4.3.0 */ public function getItem($pk = null) { Factory::getLanguage()->load('com_guidedtours.sys', JPATH_ADMINISTRATOR); $result = parent::getItem($pk); if (!empty($result->id)) { $result->title_translation = Text::_($result->title); $result->description_translation = Text::_($result->description); } return $result; } /** * Delete all steps if a tour is deleted * * @param object $pks The primary key related to the tours. * * @return boolean * * @since 4.3.0 */ public function delete(&$pks) { $pks = ArrayHelper::toInteger((array) $pks); $table = $this->getTable(); // Include the plugins for the delete events. PluginHelper::importPlugin($this->events_map['delete']); // Iterate the items to delete each one. foreach ($pks as $i => $pk) { if ($table->load($pk)) { if ($this->canDelete($table)) { $context = $this->option . '.' . $this->name; // Trigger the before delete event. $result = Factory::getApplication()->triggerEvent($this->event_before_delete, [$context, $table]); if (\in_array(false, $result, true)) { $this->setError($table->getError()); return false; } $tourId = $table->id; if (!$table->delete($pk)) { $this->setError($table->getError()); return false; } // Delete of the tour has been successful, now delete the steps $db = $this->getDatabase(); $query = $db->getQuery(true) ->delete($db->quoteName('#__guidedtour_steps')) ->where($db->quoteName('tour_id') . '=' . $tourId); $db->setQuery($query); $db->execute(); // Trigger the after event. Factory::getApplication()->triggerEvent($this->event_after_delete, [$context, $table]); } else { // Prune items that you can't change. unset($pks[$i]); $error = $this->getError(); if ($error) { Log::add($error, Log::WARNING, 'jerror'); return false; } else { Log::add(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), Log::WARNING, 'jerror'); return false; } } } else { $this->setError($table->getError()); return false; } } // Clear the component's cache $this->cleanCache(); return true; } /** * Duplicate all steps if a tour is duplicated * * @param object $pks The primary key related to the tours. * * @return boolean * * @since 4.3.0 */ public function duplicate(&$pks) { $user = $this->getCurrentUser(); $db = $this->getDatabase(); // Access checks. if (!$user->authorise('core.create', 'com_guidedtours')) { throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); } $table = $this->getTable(); $date = Factory::getDate()->toSql(); foreach ($pks as $pk) { if ($table->load($pk, true)) { // Reset the id to create a new record. $table->id = 0; $table->published = 0; if (!$table->check() || !$table->store()) { throw new \Exception($table->getError()); } $pk = (int) $pk; $query = $db->getQuery(true) ->select( $db->quoteName( [ 'title', 'description', 'ordering', 'position', 'target', 'type', 'interactive_type', 'url', 'created', 'modified', 'checked_out_time', 'checked_out', 'language', 'note', ] ) ) ->from($db->quoteName('#__guidedtour_steps')) ->where($db->quoteName('tour_id') . ' = :id') ->bind(':id', $pk, ParameterType::INTEGER); $db->setQuery($query); $rows = $db->loadObjectList(); if ($rows) { $query = $db->getQuery(true) ->insert($db->quoteName('#__guidedtour_steps')) ->columns( [ $db->quoteName('tour_id'), $db->quoteName('title'), $db->quoteName('description'), $db->quoteName('ordering'), $db->quoteName('position'), $db->quoteName('target'), $db->quoteName('type'), $db->quoteName('interactive_type'), $db->quoteName('url'), $db->quoteName('created'), $db->quoteName('created_by'), $db->quoteName('modified'), $db->quoteName('modified_by'), $db->quoteName('language'), $db->quoteName('note'), ] ); foreach ($rows as $step) { $dataTypes = [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ]; $query->values( implode( ',', $query->bindArray( [ $table->id, $step->title, $step->description, $step->ordering, $step->position, $step->target, $step->type, $step->interactive_type, $step->url, $date, $user->id, $date, $user->id, $step->language, $step->note, ], $dataTypes ) ) ); } $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); return false; } } } else { throw new \Exception($table->getError()); } } // Clear tours cache $this->cleanCache(); return true; } /** * Sets a tour's steps language * * @param int $id Id of a tour * @param string $language The language to apply to the steps belong the tour * * @return boolean * * @since 4.3.0 */ protected function setStepsLanguage(int $id, string $language = '*'): bool { if ($id <= 0) { return false; } $db = $this->getDatabase(); $query = $db->getQuery(true) ->update($db->quoteName('#__guidedtour_steps')) ->set($db->quoteName('language') . ' = :language') ->where($db->quoteName('tour_id') . ' = :tourId') ->bind(':language', $language) ->bind(':tourId', $id, ParameterType::INTEGER); return $db->setQuery($query) ->execute(); } }