From 12a1274d587099f1ba4ae00cc55789978fc132a4 Mon Sep 17 00:00:00 2001 From: Dimitris Grammatikogiannis Date: Mon, 26 Jun 2023 09:41:36 +0200 Subject: [PATCH] [5.0] Allow Joomla be served from a public* folder (#40509) --------- Signed-off-by: Dimitris Grammatikogiannis Co-authored-by: Harald Leithner --- administrator/includes/app.php | 8 +++-- administrator/includes/defines.php | 1 + administrator/includes/framework.php | 6 +++- administrator/index.php | 2 +- api/includes/app.php | 4 +++ api/includes/defines.php | 1 + build/build-modules-js/error-pages.es6.js | 12 +++---- build/build-modules-js/settings.json | 8 ++--- cli/joomla.php | 4 +++ includes/app.php | 8 +++-- includes/defines.php | 1 + includes/framework.php | 6 +++- includes/incompatible.html | 38 +++++++++++++++++++++++ index.php | 2 +- installation/includes/defines.php | 1 + libraries/src/HTML/HTMLHelper.php | 18 +++++------ tests/Unit/bootstrap.php | 4 +++ 17 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 includes/incompatible.html diff --git a/administrator/includes/app.php b/administrator/includes/app.php index 2f9ed924ec0cb..b281b69d71172 100644 --- a/administrator/includes/app.php +++ b/administrator/includes/app.php @@ -22,9 +22,13 @@ require_once JPATH_BASE . '/includes/defines.php'; } +if (!defined('JPATH_PUBLIC')) { + define('JPATH_PUBLIC', JPATH_ROOT); +} + // Check for presence of vendor dependencies not included in the git repository -if (!file_exists(JPATH_LIBRARIES . '/vendor/autoload.php') || !is_dir(JPATH_ROOT . '/media/vendor')) { - echo file_get_contents(JPATH_ROOT . '/templates/system/build_incomplete.html'); +if (!file_exists(JPATH_LIBRARIES . '/vendor/autoload.php') || !is_dir(JPATH_PUBLIC . '/media/vendor')) { + echo file_get_contents(JPATH_BASE . '/templates/system/build_incomplete.html'); exit; } diff --git a/administrator/includes/defines.php b/administrator/includes/defines.php index 3e8a3fe5fb526..ddf7c93e779e5 100644 --- a/administrator/includes/defines.php +++ b/administrator/includes/defines.php @@ -16,6 +16,7 @@ // Defines define('JPATH_ROOT', implode(DIRECTORY_SEPARATOR, $parts)); define('JPATH_SITE', JPATH_ROOT); +define('JPATH_PUBLIC', JPATH_ROOT); define('JPATH_CONFIGURATION', JPATH_ROOT); define('JPATH_ADMINISTRATOR', JPATH_ROOT . DIRECTORY_SEPARATOR . 'administrator'); define('JPATH_LIBRARIES', JPATH_ROOT . DIRECTORY_SEPARATOR . 'libraries'); diff --git a/administrator/includes/framework.php b/administrator/includes/framework.php index 10c770cfe29af..248f3fb7c7bc1 100644 --- a/administrator/includes/framework.php +++ b/administrator/includes/framework.php @@ -22,7 +22,11 @@ || (file_exists(JPATH_INSTALLATION . '/index.php') && (false === (new Version())->isInDevelopmentState())) ) { if (file_exists(JPATH_INSTALLATION . '/index.php')) { - header('Location: ../installation/index.php'); + if (JPATH_ROOT === JPATH_PUBLIC) { + header('Location: ../installation/index.php'); + } else { + echo 'Installation from a public folder is not supported, revert your Server configuration to point at the Joomla\'s root folder to continue.'; + } exit(); } else { diff --git a/administrator/index.php b/administrator/index.php index 6aec14a36bb8c..75d1d5fb55a8e 100644 --- a/administrator/index.php +++ b/administrator/index.php @@ -17,7 +17,7 @@ str_replace( '{{phpversion}}', JOOMLA_MINIMUM_PHP, - file_get_contents(dirname(__FILE__) . '/../templates/system/incompatible.html') + file_get_contents(dirname(dirname(__FILE__)) . '/includes/incompatible.html') ) ); } diff --git a/api/includes/app.php b/api/includes/app.php index 9f10825f9f10b..d55fc47a3c6cd 100644 --- a/api/includes/app.php +++ b/api/includes/app.php @@ -22,6 +22,10 @@ require_once JPATH_BASE . '/includes/defines.php'; } +if (!defined('JPATH_PUBLIC')) { + define('JPATH_PUBLIC', JPATH_ROOT); +} + require_once JPATH_BASE . '/includes/framework.php'; // Set profiler start time and memory usage and mark afterLoad in the profiler. diff --git a/api/includes/defines.php b/api/includes/defines.php index 6148b98c0969d..09df2661f67d3 100644 --- a/api/includes/defines.php +++ b/api/includes/defines.php @@ -16,6 +16,7 @@ // Defines. define('JPATH_ROOT', implode(DIRECTORY_SEPARATOR, $parts)); define('JPATH_SITE', JPATH_ROOT); +define('JPATH_PUBLIC', JPATH_ROOT); define('JPATH_CONFIGURATION', JPATH_ROOT); define('JPATH_ADMINISTRATOR', JPATH_ROOT . DIRECTORY_SEPARATOR . 'administrator'); define('JPATH_LIBRARIES', JPATH_ROOT . DIRECTORY_SEPARATOR . 'libraries'); diff --git a/build/build-modules-js/error-pages.es6.js b/build/build-modules-js/error-pages.es6.js index 1dc8d7e3f2ce1..a51b65cf477b4 100644 --- a/build/build-modules-js/error-pages.es6.js +++ b/build/build-modules-js/error-pages.es6.js @@ -147,14 +147,12 @@ module.exports.createErrorPages = async (options) => { await mkdir(dirname(`${RootPath}${options.settings.errorPages[name].destFile}`), { recursive: true, mode: 0o755 }); } - await writeFile( - `${RootPath}${options.settings.errorPages[name].destFile}`, - template, - { encoding: 'utf8', mode: 0o644 }, - ); + options.settings.errorPages[name].destFile.forEach(async (folder) => { + await writeFile(`${RootPath}${folder}`, template, { encoding: 'utf8', mode: 0o644 }); - // eslint-disable-next-line no-console - console.error(`✅ Created the file: ${options.settings.errorPages[name].destFile}`); + // eslint-disable-next-line no-console + console.error(`✅ Created the file: ${folder}`); + }); }; Object.keys(options.settings.errorPages).forEach((name) => processPages.push(processPage(name))); diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json index 77797fdd9d277..603b9c159639c 100644 --- a/build/build-modules-js/settings.json +++ b/build/build-modules-js/settings.json @@ -798,7 +798,7 @@ "text": "It looks like you are trying to run Joomla! from our git repository. To do so requires you complete a couple of extra steps first.", "link": "J4.x:Setting_Up_Your_Local_Environment", "linkText": "More Details", - "destFile": "/templates/system/build_incomplete.html" + "destFile": ["/templates/system/build_incomplete.html"] }, "unsupported": { "title": "Joomla: unsupported PHP version", @@ -806,7 +806,7 @@ "text": "Your host needs to use PHP version {{phpversion}} or newer to run this version of Joomla!", "link": "J4.x:Unsupported_PHP_Version", "linkText": "Help me resolve this", - "destFile": "/templates/system/incompatible.html" + "destFile": ["/templates/system/incompatible.html", "/includes/incompatible.html"] }, "noxml": { "title": "Joomla: Missing PHP-XML library", @@ -814,7 +814,7 @@ "text": "Your host needs to use PHP with support for the XML library to run this version of Joomla!", "link": "J4.x:Missing_XML_Library", "linkText": "Help me resolve this", - "destFile": "/media/system/html/noxml.html" + "destFile": ["/media/system/html/noxml.html"] }, "fatal": { "title": "An Error Occurred: {{statusText}}", @@ -822,7 +822,7 @@ "text": "The server returned a \"{{statusCode_statusText}}\"", "link": "J4.x:FatalError", "linkText": "Help me resolve this", - "destFile": "/templates/system/fatal-error.html" + "destFile": ["/templates/system/fatal-error.html"] } } } diff --git a/cli/joomla.php b/cli/joomla.php index c0cf73258a638..5e5364ef11619 100755 --- a/cli/joomla.php +++ b/cli/joomla.php @@ -43,6 +43,10 @@ exit; } +if (!defined('JPATH_PUBLIC')) { + define('JPATH_PUBLIC', JPATH_ROOT); +} + // Check if installed if ( !file_exists(JPATH_CONFIGURATION . '/configuration.php') diff --git a/includes/app.php b/includes/app.php index b50005044fb99..394da7f94c4ed 100644 --- a/includes/app.php +++ b/includes/app.php @@ -22,9 +22,13 @@ require_once JPATH_BASE . '/includes/defines.php'; } +if (!defined('JPATH_PUBLIC')) { + define('JPATH_PUBLIC', JPATH_ROOT); +} + // Check for presence of vendor dependencies not included in the git repository -if (!file_exists(JPATH_LIBRARIES . '/vendor/autoload.php') || !is_dir(JPATH_ROOT . '/media/vendor')) { - echo file_get_contents(JPATH_ROOT . '/templates/system/build_incomplete.html'); +if (!file_exists(JPATH_LIBRARIES . '/vendor/autoload.php') || !is_dir(JPATH_PUBLIC . '/media/vendor')) { + echo file_get_contents(JPATH_BASE . '/templates/system/build_incomplete.html'); exit; } diff --git a/includes/defines.php b/includes/defines.php index a0d6d924b5516..179cb9b9d89a2 100644 --- a/includes/defines.php +++ b/includes/defines.php @@ -16,6 +16,7 @@ define('JPATH_ROOT', implode(DIRECTORY_SEPARATOR, $parts)); define('JPATH_SITE', JPATH_ROOT); define('JPATH_CONFIGURATION', JPATH_ROOT); +define('JPATH_PUBLIC', JPATH_ROOT); define('JPATH_ADMINISTRATOR', JPATH_ROOT . DIRECTORY_SEPARATOR . 'administrator'); define('JPATH_LIBRARIES', JPATH_ROOT . DIRECTORY_SEPARATOR . 'libraries'); define('JPATH_PLUGINS', JPATH_ROOT . DIRECTORY_SEPARATOR . 'plugins'); diff --git a/includes/framework.php b/includes/framework.php index 69130d7cfe395..2ea0e5dc4baf4 100644 --- a/includes/framework.php +++ b/includes/framework.php @@ -22,7 +22,11 @@ || (file_exists(JPATH_INSTALLATION . '/index.php') && (false === (new Version())->isInDevelopmentState())) ) { if (file_exists(JPATH_INSTALLATION . '/index.php')) { - header('Location: ' . substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], 'index.php')) . 'installation/index.php'); + if (JPATH_ROOT === JPATH_PUBLIC) { + header('Location: ' . substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], 'index.php')) . 'installation/index.php'); + } else { + echo 'Installation from a public folder is not supported, revert your Server configuration to point at the Joomla\'s root folder to continue.'; + } exit; } else { diff --git a/includes/incompatible.html b/includes/incompatible.html new file mode 100644 index 0000000000000..ae42c29b990e8 --- /dev/null +++ b/includes/incompatible.html @@ -0,0 +1,38 @@ + + + + + + + Joomla: unsupported PHP version + + + + +
+
+
+

Sorry, your PHP version is not supported

+

Your host needs to use PHP version {{phpversion}} or newer to run this version of Joomla!

+

Help me resolve this

+ + + + + + + + +
+ +
+
+ + + diff --git a/index.php b/index.php index e3f4ef5d4530a..85daa024dce05 100644 --- a/index.php +++ b/index.php @@ -17,7 +17,7 @@ str_replace( '{{phpversion}}', JOOMLA_MINIMUM_PHP, - file_get_contents(dirname(__FILE__) . '/templates/system/incompatible.html') + file_get_contents(dirname(__FILE__) . '/includes/incompatible.html') ) ); } diff --git a/installation/includes/defines.php b/installation/includes/defines.php index 9ae71a84dc859..1f94b7a344471 100644 --- a/installation/includes/defines.php +++ b/installation/includes/defines.php @@ -17,6 +17,7 @@ // Defines define('JPATH_ROOT', implode(DIRECTORY_SEPARATOR, $parts)); define('JPATH_SITE', JPATH_ROOT); +define('JPATH_PUBLIC', JPATH_ROOT); define('JPATH_CONFIGURATION', JPATH_ROOT); define('JPATH_ADMINISTRATOR', JPATH_ROOT . DIRECTORY_SEPARATOR . 'administrator'); define('JPATH_LIBRARIES', JPATH_ROOT . DIRECTORY_SEPARATOR . 'libraries'); diff --git a/libraries/src/HTML/HTMLHelper.php b/libraries/src/HTML/HTMLHelper.php index baa94462301c6..7c8a9ce3e0805 100644 --- a/libraries/src/HTML/HTMLHelper.php +++ b/libraries/src/HTML/HTMLHelper.php @@ -401,7 +401,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec if ($template->inheritable || !empty($template->parent)) { $client = $app->isClient('administrator') === true ? 'administrator' : 'site'; - $templaPath = JPATH_ROOT . "/media/templates/$client"; + $templaPath = JPATH_PUBLIC . "/media/templates/$client"; } // For each potential files @@ -441,7 +441,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec list($element, $file) = explode('/', $file, 2); // Try to deal with plugins group in the media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$element/$folder/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/$extension/$element/$folder/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -450,7 +450,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } // Try to deal with classical file in a media subfolder called element - $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$folder/$element/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/$extension/$folder/$element/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -477,7 +477,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } } else { // Try to deal with system files in the media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$element/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/system/$folder/$element/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -487,7 +487,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } } else { // Try to deal with files in the extension's media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$folder/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/$extension/$folder/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -524,7 +524,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } // Try to deal with system files in the media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/system/$folder/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -534,7 +534,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec } } else { // Try to deal with system files in the media folder - $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$file", $ext, $debugMode); + $found = static::addFileToBuffer(JPATH_PUBLIC . "/media/system/$folder/$file", $ext, $debugMode); if (!empty($found)) { $includes[] = $found; @@ -558,7 +558,7 @@ protected static function includeRelativeFiles($folder, $file, $relative, $detec * This MD5SUM file must represent the signature of the folder content */ foreach ($files as $file) { - $path = JPATH_ROOT . "/$file"; + $path = JPATH_PUBLIC . '/' . $file; $found = static::addFileToBuffer($path, $ext, $debugMode); @@ -1209,7 +1209,7 @@ protected static function addFileToBuffer($path = '', $ext = '', $debugMode = fa */ protected static function convertToRelativePath($path) { - $relativeFilePath = Uri::root(true) . str_replace(JPATH_ROOT, '', $path); + $relativeFilePath = Uri::root(true) . str_replace(JPATH_PUBLIC, '', $path); // On windows devices we need to replace "\" with "/" otherwise some browsers will not load the asset return str_replace(DIRECTORY_SEPARATOR, '/', $relativeFilePath); diff --git a/tests/Unit/bootstrap.php b/tests/Unit/bootstrap.php index 0d922f8161618..6d47f10dec7c4 100644 --- a/tests/Unit/bootstrap.php +++ b/tests/Unit/bootstrap.php @@ -35,6 +35,10 @@ define('JPATH_ROOT', JPATH_BASE); } +if (!defined('JPATH_PUBLIC')) { + define('JPATH_PUBLIC', JPATH_ROOT); +} + /** * @deprecated 4.4.0 will be removed in 6.0 **/