fix(prestashop): image edubox-prestashop fonctionne en local et derrière proxy

- edubox-tools.patch : getShopDomain/Ssl conservent les ports non standards
- edubox-configuration.patch : PS_SHOP_DOMAIN, _PS_BASE_URL_, PS_SSL_ENABLED… résolus dynamiquement
- edubox-shop-getbaseurl.patch : Shop::getBaseURL() utilise le host de la requête
- edubox-shopurl.patch : getMainShopDomain conserve les ports non standards
- edubox-clear-cache-init.sh : vidage des caches à chaque démarrage
- seed.ts : passage au tag 9-edubox-9
- README mis à jour avec les nouveaux patches
This commit is contained in:
EduBox Dev
2026-06-23 16:39:12 +00:00
parent 8a9deb8ebc
commit 73b561ed33
21 changed files with 651 additions and 1 deletions
+52
View File
@@ -0,0 +1,52 @@
FROM prestashop/prestashop:9
# Apply EduBox patches so PrestaShop 9 works behind the dynamic-domain reverse proxy.
COPY edubox-tools.patch \
edubox-link.patch \
edubox-frontcontroller.patch \
edubox-shop.patch \
edubox-shopurl.patch \
edubox-shop-getbaseurl.patch \
edubox-shopcontext.patch \
edubox-asseturl.patch \
edubox-install.patch \
edubox-install-language.patch \
edubox-language.patch \
edubox-configuration.patch \
edubox-dashboard-warning.patch \
edubox-docker-run.patch \
/tmp/
RUN patch -p1 -d /var/www/html < /tmp/edubox-tools.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-link.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-frontcontroller.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-shop.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-shopurl.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-shop-getbaseurl.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-shopcontext.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-asseturl.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-install.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-install-language.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-language.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-configuration.patch && \
patch -p1 -d /var/www/html < /tmp/edubox-dashboard-warning.patch && \
patch -p1 -d / < /tmp/edubox-docker-run.patch && \
rm /tmp/edubox-*.patch
# Apache proxy configuration
COPY proxy.conf /etc/apache2/conf-enabled/edubox-proxy.conf
# Pre-download French translation pack so the installer works offline.
# Agents may not have outbound internet access during installation.
# The official image copies /tmp/data-ps/prestashop/ into /var/www/html on first
# boot, so we place the pack there as well.
COPY translations-symfony-fr-FR.zip /tmp/data-ps/prestashop/translations/sf-fr-FR.zip
RUN chown -R www-data:www-data /tmp/data-ps/prestashop/translations
# Early bootstrap normalisation for X-Forwarded-* headers
COPY defines_custom.inc.php /var/www/html/config/defines_custom.inc.php
# Clear caches on every start so dynamic domains/ports are picked up
COPY edubox-clear-cache-init.sh /tmp/init-scripts/edubox-clear-cache.sh
RUN chmod +x /tmp/init-scripts/edubox-clear-cache.sh
RUN chown -R www-data:www-data /var/www/html
+99
View File
@@ -0,0 +1,99 @@
# EduBox PrestaShop 9 Image
Image Docker patchée basée sur `prestashop/prestashop:9`, conçue pour fonctionner
avec le reverse proxy dynamique d'EduBox.
## Pourquoi une image patchée ?
PrestaShop 9 (Apache 2.4 + PHP 8.5) a plusieurs problèmes majeurs derrière EduBox :
1. Les headers `X-Forwarded-*` sont corrompus par Apache/PHP : `$_SERVER` les
reçoit sous forme d'arrays au lieu de strings. On contourne ce bug via
`getenv()` dans `config/defines_custom.inc.php`.
2. PrestaShop utilise partout le domaine stocké en base (`ps_shop_url`) et la
configuration `PS_SSL_ENABLED`. Derrière EduBox, le domaine public change à
chaque instance (`<id>.alfrednobel.edudeploy.com`) et toutes les requêtes
publiques arrivent en HTTPS. Les patches forcent l'utilisation de l'hôte et
du protocole de la requête courante.
3. Les agents étudiants peuvent être hors ligne. Le pack de langue français est
donc embarqué dans l'image pour éviter tout téléchargement pendant
l'installation.
## Build local
```bash
cd /opt/edubox/prestashop-image
docker build -t edubox-prestashop:9 .
```
## Push sur le registry Gitea
```bash
docker tag edubox-prestashop:9 \
151.80.60.98:3001/yacine/edubox/edubox-prestashop:9-edubox-9
docker push \
151.80.60.98:3001/yacine/edubox/edubox-prestashop:9-edubox-9
```
## Patches appliqués
| Patch | Fichier modifié | Objectif |
|-------|-----------------|----------|
| `edubox-tools.patch` | `classes/Tools.php` | `getShopDomain()` / `getShopDomainSsl()` utilisent `getHttpHost()` dynamiquement en conservant les ports non standards (ex. `localhost:8088`) ; `.htaccess` généré sans condition `HTTP_HOST` (images/catégories). |
| `edubox-link.patch` | `classes/Link.php` | `getBaseLink()` et `getAdminBaseLink()` utilisent `usingSecureMode()` et `getHttpHost()`. |
| `edubox-frontcontroller.patch` | `classes/controller/FrontController.php` | Désactive `sslRedirection()` pour éviter les boucles HTTP/HTTPS. |
| `edubox-shop.patch` | `classes/shop/Shop.php` | `Shop::initialize()` utilise le shop par défaut sans redirection forcée. |
| `edubox-shopurl.patch` | `classes/shop/ShopUrl.php` | `getMainShopDomain()` / `getMainShopDomainSSL()` retournent le domaine de la requête en conservant les ports non standards. |
| `edubox-shop-getbaseurl.patch` | `classes/shop/Shop.php` | `Shop::getBaseURL()` utilise le host/port de la requête courante. |
| `edubox-shopcontext.patch` | `src/Core/Context/ShopContext.php` | `getBaseURL()` du BO est reconstruit à partir de la requête courante. |
| `edubox-configuration.patch` | `classes/Configuration.php` | `PS_SHOP_DOMAIN`, `PS_SHOP_DOMAIN_SSL`, `PS_SSL_ENABLED`, `_PS_BASE_URL_`, `_PS_BASE_URL_SSL_` sont résolus dynamiquement depuis la requête, pas depuis le cache DB. |
| `edubox-asseturl.patch` | `src/Adapter/Assets/AssetUrlGeneratorTrait.php` | Les assets CCC utilisent le protocole de la requête, pas `PS_SSL_ENABLED`. |
| `edubox-install.patch` | `src/PrestaShopBundle/Install/Install.php` | `finalize()` respecte `PS_FOLDER_ADMIN` (évite le bug overlayfs `admin``admin-edubox`). |
| `edubox-install-language.patch` | `src/PrestaShopBundle/Install/Install.php` | Évite le téléchargement du pack legacy `fr.gzip` quand le pack Symfony est embarqué. |
| `edubox-language.patch` | `classes/Language.php` | Utilise `_PS_TRANSLATIONS_DIR_` au runtime pour le cache langue ; évite le téléchargement réseau si le pack est présent. |
| `edubox-dashboard-warning.patch` | `controllers/admin/AdminDashboardController.php` | Désactive le bandeau davertissement "domaine différent de SEO & URL". |
| `edubox-docker-run.patch` | `/tmp/docker_run.sh` | Supprime un `install.lock` résiduel si une installation précédente a échoué. |
## Fichiers injectés
- `proxy.conf` : Apache truste `X-Forwarded-Proto: https` pour positionner
`HTTPS=on` dans l'environnement PHP. Active aussi `AllowOverride All` pour
que le `.htaccess` de PrestaShop fonctionne.
- `config/defines_custom.inc.php` : normalise `HTTP_X_FORWARDED_HOST`,
`HTTP_X_FORWARDED_PROTO` et `HTTP_HOST` corrompus ; définit
`PS_TRUSTED_PROXIES` pour Symfony.
- `translations-symfony-fr-FR.zip` → copié sous `sf-fr-FR.zip` dans
`/var/www/html/translations/` : pack de langue Symfony français embarqué
( PrestaShop attend le préfixe `sf-` ).
- `edubox-clear-cache-init.sh``/tmp/init-scripts/edubox-clear-cache.sh` :
vidage des caches Smarty/Symfony et des assets CCC à chaque démarrage du
conteneur, afin que les changements de domaine/port soient pris en compte.
## Utilisation dans EduBox
Le template PrestaShop 9 dans `server/prisma/seed.ts` utilise cette image :
```yaml
app:
image: 151.80.60.98:3001/yacine/edubox/edubox-prestashop:9-edubox-8
```
## Mise à jour vers une nouvelle version de PrestaShop
Si PrestaShop sort une version `9.x.y` :
1. Modifier le `FROM` du Dockerfile : `FROM prestashop/prestashop:9.x.y`
2. Relancer le build. Les patches qui échouent doivent être adaptés aux
nouvelles lignes/code de PrestaShop.
3. Re-tagger et pousser : `9.x.y-edubox-1`.
4. Mettre à jour `server/prisma/seed.ts` avec le nouveau tag.
## Déploiement sur les agents
L'image doit être accessible depuis chaque agent étudiant. Deux options :
1. **Registry privé** (recommandé) : tagger et pousser l'image sur un registry
(Docker Hub, registry Gitea, GHCR, etc.) puis mettre à jour
`server/prisma/seed.ts` avec le nom complet.
2. **Build manuel sur chaque agent** : copier ce dossier sur l'agent et lancer
`docker build` avant le premier déploiement.
+34
View File
@@ -0,0 +1,34 @@
<?php
/**
* EduBox reverse proxy normalisation for PrestaShop 9 running behind the
* EduBox dynamic-public-domain resolver.
*
* The official PrestaShop 9 + PHP 8.5 + Apache image has a bug where
* X-Forwarded-* headers are exposed to PHP as arrays whose value is the
* header name. getenv() returns the correct string, so we use it to
* reconstruct $_SERVER entries used by Tools::getHttpHost/ShopDomainSSL.
*/
if ($val = getenv('HTTP_X_FORWARDED_HOST')) {
$_SERVER['HTTP_X_FORWARDED_HOST'] = $val;
}
if ($val = getenv('HTTP_X_FORWARDED_PROTO')) {
$_SERVER['HTTP_X_FORWARDED_PROTO'] = $val;
}
// Apache/PHP 8.5 sometimes corrupts HTTP_HOST into an array; fall back safely.
if (!empty($_SERVER['HTTP_HOST']) && is_array($_SERVER['HTTP_HOST'])) {
$_SERVER['HTTP_HOST'] = !empty($_SERVER['SERVER_NAME']) && !is_array($_SERVER['SERVER_NAME'])
? $_SERVER['SERVER_NAME']
: (getenv('HTTP_X_FORWARDED_HOST') ?: 'localhost');
}
if (!empty($_SERVER['HTTPS']) && is_array($_SERVER['HTTPS'])) {
$_SERVER['HTTPS'] = 'off';
}
// Tell Symfony to trust the EduBox resolver so $request->isSecure() and
// $request->getHost() honour X-Forwarded-* headers.
putenv('PS_TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR');
$_SERVER['PS_TRUSTED_PROXIES'] = '127.0.0.1,REMOTE_ADDR';
$_ENV['PS_TRUSTED_PROXIES'] = '127.0.0.1,REMOTE_ADDR';
+20
View File
@@ -0,0 +1,20 @@
--- a/src/Adapter/Assets/AssetUrlGeneratorTrait.php
+++ b/src/Adapter/Assets/AssetUrlGeneratorTrait.php
@@ -49,12 +49,14 @@ trait AssetUrlGeneratorTrait
protected function getFQDN()
{
if (null === $this->fqdn) {
- if ($this->configuration->get('PS_SSL_ENABLED') && ToolsLegacy::usingSecureMode()) {
- $this->fqdn = $this->configuration->get('_PS_BASE_URL_SSL_');
- } else {
+ // EduBox: rely on the current request security, not on PS_SSL_ENABLED.
+ // Behind the reverse proxy every public request is HTTPS.
+ if (ToolsLegacy::usingSecureMode()) {
+ $this->fqdn = $this->configuration->get('_PS_BASE_URL_SSL_') ?: $this->configuration->get('_PS_BASE_URL_');
+ } else {
$this->fqdn = $this->configuration->get('_PS_BASE_URL_');
}
}
return $this->fqdn;
}
@@ -0,0 +1,10 @@
#!/bin/bash
# EduBox: clear PrestaShop caches at every container start so that dynamic
# domains/ports (localhost:PORT or reverse-proxy public URL) are picked up.
echo "* EduBox: clearing PrestaShop caches for dynamic domain..."
rm -rf /var/www/html/var/cache/*
rm -rf /var/www/html/app/cache/*
rm -rf /var/www/html/cache/smarty/cache/*
rm -rf /var/www/html/cache/smarty/compile/*
rm -rf /var/www/html/themes/*/assets/cache/*
rm -rf /var/www/html/img/tmp/*
@@ -0,0 +1,36 @@
--- a/classes/Configuration.php 2026-06-04 14:48:44.000000000 +0000
+++ b/classes/Configuration.php 2026-06-23 16:27:03.944472677 +0000
@@ -210,6 +210,33 @@
Configuration::loadConfiguration();
}
+ // EduBox: dynamic public domains and ports (local access + reverse proxy).
+ // These keys must be resolved from the current request, not from the DB cache.
+ if ($key === 'PS_SHOP_DOMAIN' || $key === 'PS_SHOP_DOMAIN_SSL') {
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+ return $host;
+ }
+ if ($key === 'PS_SSL_ENABLED' || $key === 'PS_SSL_ENABLED_EVERYWHERE') {
+ return Tools::usingSecureMode() ? '1' : '0';
+ }
+ if ($key === '_PS_BASE_URL_') {
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+ return 'http://' . $host;
+ }
+ if ($key === '_PS_BASE_URL_SSL_') {
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+ return 'https://' . $host;
+ }
+
$idLang = self::isLangKey($key) ? (int) $idLang : 0;
if (self::$_new_cache_shop === null) {
@@ -0,0 +1,49 @@
--- a/controllers/admin/AdminDashboardController.php
+++ b/controllers/admin/AdminDashboardController.php
@@ -330,43 +330,9 @@
protected function getWarningDomainName()
{
- $warning = false;
- if (Shop::isFeatureActive()) {
- return;
- }
-
- $shop = Context::getContext()->shop;
- if ($_SERVER['HTTP_HOST'] != $shop->domain && $_SERVER['HTTP_HOST'] != $shop->domain_ssl && Tools::getValue('ajax') == false) {
- $warning = $this->trans('You are currently connected under the following domain name:', [], 'Admin.Dashboard.Notification') . ' <span style="color: #CC0000;">' . $_SERVER['HTTP_HOST'] . '</span><br />';
- if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE')) {
- $warning .= $this->trans(
- 'This is different from the shop domain name set in the Multistore settings: "%s".',
- [
- '%s' => $shop->domain,
- ],
- 'Admin.Dashboard.Notification'
- ) . $this->trans(
- 'If this is your main domain, please {link}change it now{/link}.',
- [
- '{link}' => '<a href="' . $this->context->link->getAdminLink('AdminShopUrl', true, [], ['id_shop_url' => (int) $shop->id, 'updateshop_url' => 1]) . '">',
- '{/link}' => '</a>',
- ],
- 'Admin.Dashboard.Notification'
- );
- } else {
- $warning .= $this->trans('This is different from the domain name set in the "SEO & URLs" tab.', [], 'Admin.Dashboard.Notification') . '
- ' . $this->trans(
- 'If this is your main domain, please {link}change it now{/link}.',
- [
- '{link}' => '<a href="' . $this->context->link->getAdminLink('AdminMeta') . '#meta_fieldset_shop_url">',
- '{/link}' => '</a>',
- ],
- 'Admin.Dashboard.Notification'
- );
- }
- }
-
- return $warning;
+ // EduBox: instances use dynamic public domains behind a reverse proxy.
+ // The domain stored during installation never matches the request host.
+ return false;
}
public function ajaxProcessRefreshDashboard()
+16
View File
@@ -0,0 +1,16 @@
--- a/tmp/docker_run.sh 2026-06-20 17:57:12.682339048 +0000
+++ b/tmp/docker_run.sh 2026-06-20 17:57:12.852338398 +0000
@@ -21,6 +21,13 @@
# From now, stop at error
set -e
+# EduBox: if a previous installation failed, install.lock remains but PrestaShop is not configured.
+# Remove the stale lock so the installer can run again on the next start.
+if [ -f ./install.lock ] && [ ! -f ./config/settings.inc.php ] && [ ! -f ./app/config/parameters.php ]; then
+ echo "\n* Stale install.lock detected, removing it to allow reinstallation ..."
+ rm -f ./install.lock
+fi
+
if [ ! -f ./config/settings.inc.php ] && [ ! -f ./app/config/parameters.php ] && [ ! -f ./install.lock ]; then
@@ -0,0 +1,24 @@
--- a/classes/controller/FrontController.php
+++ b/classes/controller/FrontController.php
@@ -849,18 +849,9 @@
*/
protected function sslRedirection()
{
- // If we call a SSL controller without SSL or a non SSL controller with SSL, we redirect with the right protocol
- if (Configuration::get('PS_SSL_ENABLED') && $_SERVER['REQUEST_METHOD'] != 'POST' && $this->ssl != Tools::usingSecureMode()) {
- $this->context->cookie->disallowWriting();
- header('HTTP/1.1 301 Moved Permanently');
- header('Cache-Control: no-cache');
- if ($this->ssl) {
- header('Location: ' . Tools::getShopDomainSsl(true) . $_SERVER['REQUEST_URI']);
- } else {
- header('Location: ' . Tools::getShopDomain(true) . $_SERVER['REQUEST_URI']);
- }
- exit;
- }
+ // EduBox: disabled. Behind the EduBox reverse proxy every request is
+ // served over HTTPS publicly, so PrestaShop must never redirect to HTTP.
+ return;
}
/**
@@ -0,0 +1,30 @@
--- a/src/PrestaShopBundle/Install/Install.php 2026-06-20 18:07:13.506985399 +0000
+++ b/src/PrestaShopBundle/Install/Install.php 2026-06-20 18:07:22.294363061 +0000
@@ -622,17 +622,20 @@
'locale' => (string) $xml->locale,
];
- if (file_exists(_PS_TRANSLATIONS_DIR_ . (string) $iso . '.gzip') == false) {
- $language = EntityLanguage::downloadLanguagePack($iso, _PS_INSTALL_VERSION_);
+ // EduBox: skip legacy language pack download if Symfony pack is bundled
+ $errors = [];
+ $locale = $params_lang['locale'];
+
+ if (!EntityLanguage::translationPackIsInCache($locale)) {
+ if (file_exists(_PS_TRANSLATIONS_DIR_ . (string) $iso . '.gzip') == false) {
+ $language = EntityLanguage::downloadLanguagePack($iso, _PS_INSTALL_VERSION_);
- if ($language == false) {
- throw new PrestashopInstallerException($this->translator->trans('Cannot download language pack "%iso%"', ['%iso%' => $iso], 'Install'));
+ if ($language == false) {
+ throw new PrestashopInstallerException($this->translator->trans('Cannot download language pack "%iso%"', ['%iso%' => $iso], 'Install'));
+ }
}
}
- $errors = [];
- $locale = $params_lang['locale'];
-
/* @todo check if a newer pack is available */
if (!EntityLanguage::translationPackIsInCache($locale)) {
EntityLanguage::downloadXLFLanguagePack($locale, $errors);
+9
View File
@@ -0,0 +1,9 @@
--- a/src/PrestaShopBundle/Install/Install.php
+++ b/src/PrestaShopBundle/Install/Install.php
@@ -1202,7 +1202,7 @@ class Install extends AbstractInstall
{
- $adminFolder = 'admin-dev';
+ $adminFolder = getenv('PS_FOLDER_ADMIN') ?: 'admin-dev';
// If we need, we generate a random name for admin folder (for security purpose!)
if (file_exists(_PS_ROOT_DIR_ . '/admin/')) {
+36
View File
@@ -0,0 +1,36 @@
--- a/classes/Language.php
+++ b/classes/Language.php
@@ -1235,6 +1235,12 @@
*/
public static function downloadXLFLanguagePack($locale, &$errors = [], $type = self::PACK_TYPE_SYMFONY)
{
+ // EduBox: if the translation pack is already present in the image,
+ // do not try to download it (agents may be offline).
+ if (static::translationPackIsInCache($locale, $type)) {
+ return true;
+ }
+
$file = self::getPathToCachedTranslationPack($locale, $type);
$url = (self::PACK_TYPE_EMAILS === $type) ? self::EMAILS_LANGUAGE_PACK_URL : self::SF_LANGUAGE_PACK_URL;
$url = str_replace(
@@ -1697,7 +1703,9 @@
*/
public static function translationPackIsInCache(string $locale, string $type = self::PACK_TYPE_SYMFONY): bool
{
- return file_exists(self::getPathToCachedTranslationPack($locale, $type));
+ // EduBox: use runtime constant instead of class constant, because
+ // _PS_TRANSLATIONS_DIR_ may not be defined when this file is compiled.
+ return file_exists(_PS_TRANSLATIONS_DIR_ . $type . '-' . $locale . '.zip');
}
/**
@@ -1710,7 +1718,8 @@
*/
private static function getPathToCachedTranslationPack(string $locale, string $type = self::PACK_TYPE_SYMFONY): string
{
- return self::TRANSLATION_PACK_CACHE_DIR . $type . '-' . $locale . '.zip';
+ // EduBox: use runtime constant instead of class constant.
+ return _PS_TRANSLATIONS_DIR_ . $type . '-' . $locale . '.zip';
}
/**
+46
View File
@@ -0,0 +1,46 @@
--- a/classes/Link.php 2026-06-20 20:05:45.983104609 +0000
+++ b/classes/Link.php 2026-06-20 20:05:46.195748630 +0000
@@ -862,7 +862,7 @@
public function getAdminBaseLink($idShop = null, $ssl = null, $relativeProtocol = false)
{
if (null === $ssl) {
- $ssl = Configuration::get('PS_SSL_ENABLED');
+ $ssl = Tools::usingSecureMode();
}
if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE')) {
@@ -881,9 +881,10 @@
}
if ($relativeProtocol) {
- $base = '//' . ($ssl && $this->ssl_enable ? $shop->domain_ssl : $shop->domain);
+ $base = '//' . Tools::getHttpHost(false, false, false);
} else {
- $base = (($ssl && $this->ssl_enable) ? 'https://' . $shop->domain_ssl : 'http://' . $shop->domain);
+ $protocol = Tools::usingSecureMode() ? 'https://' : 'http://';
+ $base = $protocol . Tools::getHttpHost(false, false, false);
}
return $base . $shop->getBaseURI();
@@ -1391,7 +1392,7 @@
public function getBaseLink($idShop = null, $ssl = null, $relativeProtocol = false)
{
if (null === $ssl) {
- $ssl = Configuration::get('PS_SSL_ENABLED');
+ $ssl = Tools::usingSecureMode();
}
if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') && $idShop !== null) {
@@ -1401,9 +1402,10 @@
}
if ($relativeProtocol) {
- $base = '//' . ($ssl && $this->ssl_enable ? $shop->domain_ssl : $shop->domain);
+ $base = '//' . Tools::getHttpHost(false, false, false);
} else {
- $base = (($ssl && $this->ssl_enable) ? 'https://' . $shop->domain_ssl : 'http://' . $shop->domain);
+ $protocol = Tools::usingSecureMode() ? 'https://' : 'http://';
+ $base = $protocol . Tools::getHttpHost(false, false, false);
}
return $base . $shop->getBaseURI();
@@ -0,0 +1,29 @@
--- a/classes/shop/Shop.php
+++ b/classes/shop/Shop.php
@@ -489,15 +489,16 @@ class ShopCore extends ObjectModel
*/
public function getBaseURL($auto_secure_mode = true, $add_base_uri = true)
{
- if ($auto_secure_mode && Tools::usingSecureMode()) {
- if (!$this->domain_ssl) {
- return false;
- }
- $url = 'https://' . $this->domain_ssl;
+ // EduBox: use the current request host so local access on non-standard
+ // ports (e.g. localhost:8088) and reverse-proxy domains both work.
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+
+ if ($auto_secure_mode && Tools::usingSecureMode()) {
+ $url = 'https://' . $host;
} else {
- if (!$this->domain) {
- return false;
- }
- $url = 'http://' . $this->domain;
+ $url = 'http://' . $host;
}
if ($add_base_uri) {
+46
View File
@@ -0,0 +1,46 @@
--- a/classes/shop/Shop.php
+++ b/classes/shop/Shop.php
@@ -411,38 +411,14 @@
} else {
$shop = new Shop($id_shop);
if (!Validate::isLoadedObject($shop) || !$shop->active) {
- // No shop found ... too bad, let's redirect to default shop
- $default_shop = new Shop((int) Configuration::get('PS_SHOP_DEFAULT'));
+ // EduBox: behind a reverse proxy with dynamic public domains,
+ // the requested host never matches ps_shop_url. Always use the
+ // default shop instead of redirecting to a fixed canonical URL.
+ $shop = new Shop((int) Configuration::get('PS_SHOP_DEFAULT'));
- // Hmm there is something really bad in your Prestashop !
- if (!Validate::isLoadedObject($default_shop)) {
+ if (!Validate::isLoadedObject($shop)) {
throw new PrestaShopException('Shop not found');
}
-
- $params = $_GET;
- unset($params['id_shop']);
- $url = $default_shop->domain;
- if (!Configuration::get('PS_REWRITING_SETTINGS')) {
- $url .= $default_shop->getBaseURI() . 'index.php?' . http_build_query($params);
- } else {
- // Catch url with subdomain "www"
- if (strpos($url, 'www.') === 0 && 'www.' . $_SERVER['HTTP_HOST'] === $url || $_SERVER['HTTP_HOST'] === 'www.' . $url) {
- $url .= $_SERVER['REQUEST_URI'];
- } else {
- $url .= $default_shop->getBaseURI();
- }
-
- if (count($params)) {
- $url .= '?' . http_build_query($params);
- }
- }
-
- $redirect_type = Configuration::get('PS_CANONICAL_REDIRECT');
- $redirect_code = ($redirect_type == 1 ? '302' : '301');
- $redirect_header = ($redirect_type == 1 ? 'Found' : 'Moved Permanently');
- header('HTTP/1.0 ' . $redirect_code . ' ' . $redirect_header);
- header('Location: ' . Tools::getShopProtocol() . $url);
- exit;
} elseif (defined('_PS_ADMIN_DIR_') && empty($shop->physical_uri)) {
$shop_default = new Shop((int) Configuration::get('PS_SHOP_DEFAULT'));
$shop->physical_uri = $shop_default->physical_uri;
+28
View File
@@ -0,0 +1,28 @@
--- a/src/Core/Context/ShopContext.php
+++ b/src/Core/Context/ShopContext.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace PrestaShop\PrestaShop\Core\Context;
+use Tools;
use PrestaShop\PrestaShop\Core\Domain\Shop\ValueObject\ShopConstraint;
/**
@@ -121,11 +122,12 @@ class ShopContext
public function getBaseURL(): string
{
- if ($this->secured) {
- $url = 'https://' . $this->domainSSL;
- } else {
- $url = 'http://' . $this->domain;
- }
+ // EduBox: behind a reverse proxy with dynamic public domains the shop
+ // URL stored in the database is never the real public URL. Rebuild the
+ // base URL from the current request instead.
+ $secure = Tools::usingSecureMode();
+ $domain = $secure ? Tools::getShopDomainSsl(false, false) : Tools::getShopDomain(false, false);
+ $url = ($secure ? 'https://' : 'http://') . $domain;
return $url . $this->getBaseURI();
}
+32
View File
@@ -0,0 +1,32 @@
--- a/classes/shop/ShopUrl.php
+++ b/classes/shop/ShopUrl.php
@@ -175,15 +175,23 @@
public static function getMainShopDomain($id_shop = null)
{
- ShopUrl::cacheMainDomainForShop($id_shop);
-
- return self::$main_domain[(int) $id_shop] ?? null;
+ // EduBox: dynamic public domain behind reverse proxy or direct local access.
+ // Always use the request host instead of the domain stored in database.
+ // Keep non-standard ports (e.g. localhost:8088) so local access works.
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+ return $host;
}
public static function getMainShopDomainSSL($id_shop = null)
{
- ShopUrl::cacheMainDomainForShop($id_shop);
-
- return self::$main_domain_ssl[(int) $id_shop] ?? null;
+ // EduBox: dynamic public domain behind reverse proxy or direct local access.
+ $host = Tools::getHttpHost(false, false, false);
+ if (substr($host, -3) === ':80' || substr($host, -4) === ':443') {
+ $host = substr($host, 0, strrpos($host, ':'));
+ }
+ return $host;
}
}
+44
View File
@@ -0,0 +1,44 @@
--- a/classes/Tools.php 2026-06-04 14:48:44.000000000 +0000
+++ b/classes/Tools.php 2026-06-23 16:34:13.226899992 +0000
@@ -269,8 +269,10 @@
*/
public static function getShopDomain($http = false, $entities = false)
{
- if (!$domain = ShopUrl::getMainShopDomain()) {
- $domain = Tools::getHttpHost();
+ // EduBox: dynamic domain + keep non-standard ports (e.g. localhost:8088).
+ $domain = Tools::getHttpHost(false, false, false);
+ if (substr($domain, -3) === ':80' || substr($domain, -4) === ':443') {
+ $domain = substr($domain, 0, strrpos($domain, ':'));
}
if ($entities) {
$domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8');
@@ -292,14 +294,16 @@
*/
public static function getShopDomainSsl($http = false, $entities = false)
{
- if (!$domain = ShopUrl::getMainShopDomainSSL()) {
- $domain = Tools::getHttpHost();
+ // EduBox: dynamic domain + keep non-standard ports.
+ $domain = Tools::getHttpHost(false, false, false);
+ if (substr($domain, -3) === ':80' || substr($domain, -4) === ':443') {
+ $domain = substr($domain, 0, strrpos($domain, ':'));
}
if ($entities) {
$domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8');
}
if ($http) {
- $domain = static::getProtocol((bool) Configuration::get('PS_SSL_ENABLED')) . $domain;
+ $domain = static::getProtocol(Tools::usingSecureMode()) . $domain;
}
return $domain;
@@ -2246,7 +2250,7 @@
$rewrite_settings = (int) Configuration::get('PS_REWRITING_SETTINGS', null, null, (int) $uri['id_shop']);
}
- $domain_rewrite_cond = 'RewriteCond %{HTTP_HOST} ^' . $domain . '$' . PHP_EOL;
+ $domain_rewrite_cond = ''; // EduBox: removed HTTP_HOST condition for dynamic domains
// Rewrite virtual multishop uri
if ($uri['virtual']) {
if (!$rewrite_settings) {
+10
View File
@@ -0,0 +1,10 @@
# EduBox reverse proxy handling
# Apache sees HTTP requests from the EduBox resolver. The public request is HTTPS.
SetEnvIf X-Forwarded-Proto ^https$ HTTPS=on
SetEnvIf X-Forwarded-Proto ^https$ SERVER_PORT=443
# Enable .htaccess overrides for PrestaShop URL rewriting (images, products, etc.)
<Directory /var/www/html>
AllowOverride All
Require all granted
</Directory>
Binary file not shown.
+1 -1
View File
@@ -53,7 +53,7 @@ async function main() {
{
name: "PrestaShop 9 vierge (edubox)",
type: "prestashop",
dockerImage: "151.80.60.98:3001/yacine/edubox/edubox-prestashop:9-edubox-8",
dockerImage: "151.80.60.98:3001/yacine/edubox/edubox-prestashop:9-edubox-9",
dbImage: "mariadb:10.11",
dbName: "prestashop",
dbUser: "prestashop",