shell bypass 403
<?php /** * @package admintools * @copyright Copyright (c)2010-2024 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 3, or later */ namespace Akeeba\Component\AdminTools\Administrator\Model; defined('_JEXEC') or die; use Exception; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\Session\SessionInterface; #[\AllowDynamicProperties] class DatabasetoolsModel extends BaseDatabaseModel { /** @var float The time the process started */ private $startTime = null; /** * Finds all tables using the current site's prefix * * @return array */ public function findTables() { static $ret = null; if (is_null($ret)) { $db = $this->getDatabase(); $prefix = $db->getPrefix(); $plen = strlen($prefix); $allTables = $db->getTableList(); if (empty($prefix)) { $ret = $allTables; } else { $ret = []; foreach ($allTables as $table) { if (substr($table, 0, $plen) == $prefix) { $ret[] = $table; } } } } return $ret; } public function repairAndOptimise($fromTable = null, $echo = false) { $this->resetTimer(); $tables = $this->findTables(); if (!empty($fromTable)) { $table = ''; while ($table != $fromTable) { $table = array_shift($tables); } } $db = $this->getDatabase(); while (count($tables) && $this->haveEnoughTime()) { $table = array_shift($tables); // Run a repair. On Joomla 4 we cannot run CHECK TABLE to make sure this is needed, so this always runs... if ($echo) { echo "Repairing $table\n"; } $this->executeUnpreparedQuery('REPAIR TABLE ' . $db->qn($table)); // Finally, optimize if ($echo) { echo "Optimizing $table\n"; } $this->executeUnpreparedQuery('OPTIMIZE TABLE ' . $db->qn($table)); } if (!count($tables)) { return ''; } return $table; } /** * Clean and optimize the #__sessions table. The idea is that the sessions table may get corrupt over time due to * the number of read / write operations and / or ending up with stuck phantom session records. * * @return void */ public function purgeSessions() { $db = $this->getDatabase(); try { $db->truncateTable('#__session'); $query = $db->getQuery(true) ->delete($db->quoteName('#__session')); $db->setQuery($query)->execute(); $this->executeUnpreparedQuery('OPTIMIZE TABLE ' . $db->qn('#__session')); } catch (Exception $e) { return; } } /** * Asks the Joomla 4 session object to garbage collect any open sessions. This SHOULD remove expired sessions, as * long as Joomla implements this feature for the session handler used internally in the object. * * @return void * * @since 5.7.0 */ public function garbageCollectSessions() { try { $app = Factory::getApplication(); if (!($app instanceof CMSApplication)) { return; } $session = $app->getSession(); if (!($session instanceof SessionInterface)) { return; } $session->gc(); } catch (Exception $e) { // It's OK if we fail. No harm, no foul. } } /** * Returns the current timestampt in decimal seconds */ private function microtime_float() { [$usec, $sec] = explode(" ", microtime()); return ((float) $usec + (float) $sec); } /** * Starts or resets the internal timer */ private function resetTimer() { $this->startTime = $this->microtime_float(); } /** * Makes sure that no more than 3 seconds since the start of the timer have * elapsed * * @return bool */ private function haveEnoughTime() { $now = $this->microtime_float(); $elapsed = abs($now - $this->startTime); return $elapsed < 3; } /** * Executes an unprepared SQL statement. * * The PDO driver doesn't distinguish between prepared and unprepared statements. Therefore we can just run anything * we please. The MySQLi driver, however, has a distinction between prepared and unprepared statements. We cannot * run certain SQL comments (such as OPTIMIZE and REPAIR) over a prepared statement. The MySQLi driver has a handy * method called executeUnpreparedStatement which is protected and which runs this kind of statements. * * This here method tries to figure out if the database driver object has that method and use it instead of the * prepared statement. * * @param $sql * * @return bool|mixed */ private function executeUnpreparedQuery($sql) { $db = $this->getDatabase(); $sql = $db->replacePrefix($sql); $refObj = new \ReflectionObject($db); try { $method = $refObj->getMethod('executeUnpreparedQuery'); $method->setAccessible(true); return $method->invoke($db, $sql); } catch (\ReflectionException $e) { return $db->setQuery($sql)->execute(); } } }