shell bypass 403
<?php
/**
* @package admintools
* @copyright Copyright (c)2010-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace Akeeba\Component\AdminTools\Administrator\Mixin;
defined('_JEXEC') or die();
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\String\StringHelper;
/**
* Trait to modify batchCopy for relations involving parent tables OTHER than the Joomla core categories table.
*/
trait ModelCopyTrait
{
/**
* MVC table name this records belongs to (as the leaf node of an one-to-many relation).
*
* Use "_core_categories" to use Joomla's core categories.
*
* Use null for records without parents. In this case batchCopy() clones records, modifying the title and alias.
*
* @var string
*
* @since 7.0.0
*/
protected $_parent_table = '_core_categories';
public function copy($pks)
{
return $this->batchCopy(0, $pks, []);
}
/**
* Method to check the validity of the parent table ID for batch copy and move
*
* @param integer $categoryId The parent table ID to check
*
* @return boolean
*
* @since 7.0.0
*/
protected function checkCategoryId($categoryId)
{
if ($this->_parent_table === '_core_categories')
{
return parent::checkCategoryId($categoryId);
}
// If there is no parent table only accept an empty parent table ID
if (empty($this->_parent_table))
{
return empty($categoryId);
}
if (empty($categoryId))
{
if (!method_exists($this, 'setError'))
{
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
}
/** @noinspection PhpDeprecationInspection only called when deprecated code is not removed */
$this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
return false;
}
// Check that the category exists
$categoryTable = $this->getMVCFactory()->createTable($this->_parent_table, 'Administrator');
try
{
$didLoadCategory = $categoryTable->load($categoryId);
/** @noinspection PhpDeprecationInspection qualified access will work when getError is removed */
$catError = $didLoadCategory
? ''
: (method_exists($categoryTable, 'getError') ? $categoryTable->getError() : '');
}
catch (\Exception $e)
{
$didLoadCategory = false;
$catError = $e->getMessage();
}
if (!$didLoadCategory)
{
$errorMessage = $catError ?: Text::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND');
if (!method_exists($this, 'setError'))
{
throw new \RuntimeException($errorMessage);
}
/** @noinspection PhpDeprecationInspection only called when deprecated code is not removed */
$this->setError($errorMessage);
return false;
}
// Check that the user has create permission for the component
$extension = Factory::getApplication()->getInput()->get('option', '');
$user = Factory::getApplication()->getIdentity();
// If the parent table has no asset I will only check if I can create items in the component
if (!$categoryTable->hasField('asset_id'))
{
if (!$user->authorise('core.create', $extension))
{
if (!method_exists($this, 'setError'))
{
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
}
/** @noinspection PhpDeprecationInspection only called when deprecated code is not removed */
$this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
return false;
}
return true;
}
// The parent table has an asset. Let's check if the user is allowed to create items in it.
if (!$user->authorise('core.create', $categoryTable->getAssetName()))
{
if (!method_exists($this, 'setError'))
{
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
}
/** @noinspection PhpDeprecationInspection only called when deprecated code is not removed */
$this->setError(Text::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
return false;
}
return true;
}
/**
* Method to change the title & alias.
*
* @param integer $categoryId The id of the category.
* @param string $alias The alias.
* @param string $title The title.
*
* @return array Contains the modified title and alias.
*
* @since 7.0.0
*/
protected function generateNewTitle($categoryId, $alias, $title)
{
if ($this->_parent_table === '_core_categories')
{
return parent::generateNewTitle($categoryId, $alias, $title);
}
$table = $this->getTable();
$db = $this->getDatabase();
$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
->select('*')
->from($db->quoteName($table->getTableName()));
$hasAlias = $table->hasField('alias');
$aliasField = $table->getColumnAlias('alias');
$hasCatID = $table->hasField('catid');
$catidField = $table->getColumnAlias('catid');
$hasTitle = $table->hasField('title');
$titleField = $table->getColumnAlias('title');
if ($hasAlias)
{
$query->where($db->quoteName($aliasField) . ' = :alias')
->bind(':alias', $alias);
}
if ($hasCatID)
{
$query->where($db->quoteName($catidField) . ' = :catid')
->bind(':catid', $categoryId);
}
while ($rawData = $db->setQuery($query)->loadAssoc() ?: '')
{
$table->reset();
$table->bind($rawData);
if ($hasTitle && ($title === $table->$titleField))
{
$title = StringHelper::increment($title);
}
if ($hasAlias)
{
$alias = StringHelper::increment($alias, 'dash');
$query->unbind(':alias');
$query->bind(':alias', $alias);
}
else
{
break;
}
}
return [$title, $alias];
}
}