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:
@@ -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
|
||||
@@ -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 d’avertissement "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.
|
||||
@@ -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';
|
||||
@@ -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()
|
||||
@@ -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);
|
||||
@@ -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/')) {
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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.
Reference in New Issue
Block a user