* @license GNU General Public License version 2 or later; see LICENSE.txt * * Important Notes: * - Unlike other files, this file requires multiple namespace declarations in order to overload core classes during the update process * - Also unlike other files, the normal constant defined checks must be within the global namespace declaration and can't be outside of it */ namespace { // Require the restoration environment or fail cold. Prevents direct web access. \defined('_JOOMLA_UPDATE') or die(); // Fake a miniature Joomla environment if (!\defined('_JEXEC')) { \define('_JEXEC', 1); } if (!function_exists('jimport')) { /** * This is deprecated but it may still be used in the update finalisation script. * * @param string $path Ignored. * @param string $base Ignored. * * @return boolean Always true. * * @since 1.7.0 */ function jimport(string $path, ?string $base = null): bool { // Do nothing return true; } } if (!function_exists('finalizeUpdate')) { /** * Run part of the Joomla! finalisation script, namely the part that cleans up unused files/folders * * @param string $siteRoot The root to the Joomla! site * @param string $restorePath The base path to extract.php * * @return void * * @since 3.5.1 */ function finalizeUpdate(string $siteRoot, string $restorePath): void { if (!\defined('JPATH_ROOT')) { \define('JPATH_ROOT', $siteRoot); } $filePath = JPATH_ROOT . '/administrator/components/com_admin/script.php'; if (file_exists($filePath)) { require_once $filePath; } // Make sure Joomla!'s code can figure out which files exist and need be removed clearstatcache(); // Remove obsolete files - prevents errors occurring in some system plugins if (class_exists('JoomlaInstallerScript')) { (new JoomlaInstallerScript())->deleteUnexistingFiles(); } /** * Remove autoload_psr4.php so that namespace map is re-generated on the next request. This is needed * when there are new classes added to extensions on new Joomla! release. */ $namespaceMapFile = JPATH_ROOT . '/administrator/cache/autoload_psr4.php'; if (\Joomla\CMS\Filesystem\File::exists($namespaceMapFile)) { \Joomla\CMS\Filesystem\File::delete($namespaceMapFile); } } } } namespace Joomla\CMS\Filesystem { // Fake the File class if (!class_exists('\Joomla\CMS\Filesystem\File')) { /** * File mock class * * @since 3.5.1 */ abstract class File { /** * Proxies checking a file exists to the native php version * * @param string $fileName The path to the file to be checked * * @return boolean * * @since 3.5.1 */ public static function exists(string $fileName): bool { return @file_exists($fileName); } /** * Delete a file and invalidate the PHP OPcache * * @param string $fileName The path to the file to be deleted * * @return boolean * * @since 3.5.1 */ public static function delete(string $fileName): bool { self::invalidateFileCache($fileName); return @unlink($fileName); } /** * Rename a file and invalidate the PHP OPcache * * @param string $src The path to the source file * @param string $dest The path to the destination file * * @return boolean True on success * * @since 4.0.1 */ public static function move(string $src, string $dest): bool { self::invalidateFileCache($src); $result = @rename($src, $dest); if ($result) { self::invalidateFileCache($dest); } return $result; } /** * Invalidate opcache for a newly written/deleted file immediately, if opcache* functions exist and if this was a PHP file. * * @param string $filepath The path to the file just written to, to flush from opcache * @param boolean $force If set to true, the script will be invalidated regardless of whether invalidation is necessary * * @return boolean TRUE if the opcode cache for script was invalidated/nothing to invalidate, * or FALSE if the opcode cache is disabled or other conditions returning * FALSE from opcache_invalidate (like file not found). * * @since 4.0.2 */ public static function invalidateFileCache($filepath, $force = true) { return \clearFileInOPCache($filepath); } } } // Fake the Folder class, mapping it to Restore's post-processing class if (!class_exists('\Joomla\CMS\Filesystem\Folder')) { /** * Folder mock class * * @since 3.5.1 */ abstract class Folder { /** * Proxies checking a folder exists to the native php version * * @param string $folderName The path to the folder to be checked * * @return boolean * * @since 3.5.1 */ public static function exists(string $folderName): bool { return @is_dir($folderName); } /** * Delete a folder recursively and invalidate the PHP OPcache * * @param string $folderName The path to the folder to be deleted * * @return boolean * * @since 3.5.1 */ public static function delete(string $folderName): bool { if (substr($folderName, -1) == '/') { $folderName = substr($folderName, 0, -1); } if (!@file_exists($folderName) || !@is_dir($folderName) || !is_readable($folderName)) { return false; } $di = new \DirectoryIterator($folderName); /** @var \DirectoryIterator $item */ foreach ($di as $item) { if ($item->isDot()) { continue; } if ($item->isDir()) { $status = self::delete($item->getPathname()); if (!$status) { return false; } continue; } \clearFileInOPCache($item->getPathname()); @unlink($item->getPathname()); } return @rmdir($folderName); } } } } namespace Joomla\CMS\Language { // Fake the Text class - we aren't going to show errors to people anyhow if (!class_exists('\Joomla\CMS\Language\Text')) { /** * Text mock class * * @since 3.5.1 */ abstract class Text { /** * No need for translations in a non-interactive script, so always return an empty string here * * @param string $text A language constant * * @return string * * @since 3.5.1 */ public static function sprintf(string $text): string { return ''; } } } }