Migrer un site Prestashop 1.5 entièrement en HTTPS (SSL) sans encombre (ou presque…)

Mathieu Chartier Programmation 4 commentaires

Cela faisait quelques temps que je n'avais pas replongé dans le coeur des bons vieux Prestashop d'antan, à savoir des versions 1.4 et 1.5. Comme j'imagine que vous êtes encore relativement nombreux à utiliser ces anciennes versions du CMS d'e-commerce, j'ose espérer que vous avez déjà pensé à passer l'ensemble d'un site en HTTPS, comme le souhaitent fortement les navigateurs web actuels.

Après avoir moi-même eu énormément de mal à faire une migration à 100% HTTPS, je me suis dis que cet article pourrait éclairer la lanterne de certains d'entre vous, sauf si vous préférez fouiller dans les quelques anciens articles qui ne proposent pas forcément des solutions viables (mais on ne peut pas leur en vouloir non plus tant c'est la catastrophe). La solution qui fonctionne à merveille est décrite en détail un peu plus bas dans cet article (après les deux premières sections introductives mais importantes).

Petit rappel contextuel autour de Prestashop et HTTPS (SSL)...

Avant de rentrer dans le vif du sujet, je tiens à rappeler quelques informations qui comptent pour mieux comprendre les difficultés de migration vers HTTPS (SSL) avec les anciennes versions de Prestashop (1.4 ou 1.5 notamment, mais parfois aussi pour la 1.6).

Lorsque ces versions sont sorties de terre, les équipes de Prestashop n'avaient sûrement pas imaginé que l'HTTPS prendrait un tel essor en si peu de temps. Elles avaient donc (bien) prévu d'activer le SSL dans le back-office du CMS, mais cela ne concernait globalement que le tunnel de conversion, à savoir les pages du panier, du compte, de livraison et de paiement... Les autres pages n'étaient pas pensées pour être "sécurisées" en HTTPS, comme c'était encore la coutume à l'époque (et il est difficile d'en vouloir à Prestashop pour ça...). Par conséquent, il est très facilement possible de rediriger les pages à risque en HTTPS, mais toutes les autres resteront gentiment en HTTP, comme jadis...

Qui de PHP 7 avec Prestashop 1.5 et 1.4 ?

Ajoutons à cela que Prestashop 1.4, 1.5 (voire 1.6) n'ont pas été pensés à l'époque de PHP 7 et suivants. De ce fait, beaucoup de modules et de fonctionnalités si chères aux dernières versions de PHP tombent aux oubliettes. Là encore, difficile de critiquer les équipes de Prestashop qui sont pleines de qualité, mais qui ne peuvent pas non plus être des devins quelques années avant le déploiement de PHP 7. Toutefois, il s'agit aussi d'un souci que beaucoup d'utilisateurs rencontrent, et l'idéal est de malheureusement retourner en PHP 5.6. Il faudra peut-être modifier quelques constructeurs PHP mais rien de bien méchant (en gros, il faut remplacer parfois remplacer l'ancien nom du constructeur par __construct pour que tout fonctionne sans message d'erreur).

Vous l'aurez compris, on peut activer le SSL (HTTPS) dans Prestashop 1.5, mais cela reste limité à quelques pages, alors comment procéder si nous voulons que toutes les pages activent des redirections HTTPS ? Il va falloir mettre les mains dans le cambouis, et aucune autre solution ne sera à envisager, désolé... Rappelons que les navigateurs actuels, notamment Google Chrome et Mozilla Firefox (et versions alternatives), notifient de plus en plus de pages comme non sécurisées dès que le protocole HTTP est utilisé, même si la page en elle-même n'est pas si dangereuse que cela. Il devient donc primordial d'afficher idéalement 100% des pages en HTTPS.

Prestashop 1.5 et les galères d'une redirection vers HTTPS (SSL)

Un client possédant Prestashop 1.5.5 a changé d'hébergeur, mais a malheureusement connu quelques problèmes avec certains modules comme celui de Mondial Relay (qui plante à outrance selon votre version de PHP, et qu'il est fortement conseillé de désactiver puis réactiver pour tout refaire fonctionner comme il se doit). En parallèle, il a demandé de migrer sa boutique Prestashop vers HTTPS. C'est là que les galères ont commencé...

Si l'on procède par la manière simple, voici ce qui est prévu dans Prestashop 1.4 et 1.5 :

  1. Générez un certificat SSL via votre hébergeur (souvent via Let's Encrypt puisque c'est gratuit). Cela permet d'obtenir le fameux "HTTPS", mais ne désactive pas pour autant le HTTP historique.
  2. Connectez-vous au back-office de Prestashop et rendez-vous dans "Préférences" > "Générales"
  3. Cochez "Oui" à l'option "Activez le SSL"

Activez le SSL (HTTPS) dans Prestashop 1.4 et Prestashop 1.5

Ainsi, vous venez d'activer l'HTTPS pour tout le tunnel de paiement. Dans ce cas, c'est censé fonctionner sans encombre, mais vous ne possédez pas un site entièrement en HTTPS, malgré le SSL activé côté hébergeur.

Si malgré tout vous rencontrez quelques problèmes dans certains cas, il est souvent recommandé de se rendre dans "Préférences" > "SEO et URLs" et de vérifier les options des sections "Configuration des URL" et "URL de la boutique". Souvent, il est recommandé de désactiver l'option "Rediriger automatiquement vers l'URL canonique" (uniquement en cas de bug bien sûr). L'autre solution peut être de tester le site avec des URL de boutique sans les "www" dans le nom de domaine, cela a résolu le problème de certains utilisateurs.
Dans tous les cas, il convient d'enregistrer la page afin de générer à nouveau le fichier .htaccess en charge de la configuration du serveur propre à Prestashop. Cette méthode, que vous ayez modifié des options ou non, peut s'avérer payante en cas de problème à la marge.

Solution complète : migration complète d'HTTP vers HTTPS pour Prestashop 1.5

Je rappelle que la solution trouvée ici fonctionne parfaitement pour un Prestashop 1.5.5 en PHP 5.6 sur du Apache/Nginx, mais elle pourrait aussi s'appliquer peu ou prou de la même manière pour Prestashop 1.4 ou des versions inférieures de Prestashop 1.5. Avant de trouver celle solution fonctionnelle, j'ai moi-même testé des dizaines de solutions présentées dans divers articles, dont les meilleures sources sont les suivantes :

Après avoir tout essayé, et après avoir activé le SSL comme prévu dans le CMS, je n'ai jamais pu éviter l'erreur "Too many redirects" (sur Google Chrome). En soi, il s'agit d'une erreur toute bête de redirections qui tournent en rond. On demande une URL en HTTPS, Prestashop veut absolument l'afficher en HTTP, mais on force la redirection en HTTPS, donc il tourne en boucle jusqu'au plantage...

C'est cette maudite erreur qui a eu raison de ma patience, et qui m'a forcé à trouver une autre solution que celles présentées dans les articles précédents (qui ont pourtant suffit pour certains utilisateurs). Certes, certaines idées se croisent avec les tutoriels des autres blogueurs, mais la méthode n'est pas du tout la même dans les faits.

Focus sur le comportement par défaut de Prestashop 1.5 avec HTTPS/SSL

Dans tous les cas, on vous demande de forcer la redirection HTTP vers HTTPS dans le fichier .htaccess. En soi, c'est une bonne idée, et c'est ce que l'on fait dans la très large majorité des cas de migrations vers HTTPS, quel que soit le CMS source. Dans le cas des anciennes versions de Prestashop, ce n'est malheureusement pas toujours la meilleure idée au départ, car cela fait conflit avec l'option "Activer le SSL" du back-office. Explications...

Si vous avez le SSL dans l'interface d'administration, comme cela est proposé absolument partout sur les sites et forums (et dans la documentation de Prestashop), la partie "tunnel de conversion" fonctionne en HTTPS sans encombre. En revanche, les autres URL sont forcées de rester en HTTP. Si en parallèle nous forçons les redirections 301 vers HTTPS, l'erreur "too many redirects" arrive quasiment spontanément. Si l'idée vous vient à l'esprit, amusez-vous à désactiver SSL dans le back-office, et d'un coup, presque toutes les URL sont bien redirigées en HTTPS, sauf les pages du tunnel de paiement. Et dans nos navigateurs actuels, cela bloque les transactions car des outils comme Chrome ou Firefox détectent qu'il s'agit de pages à risque non sécurisées. Pour résumer le fonctionnement par défaut dans certains anciens Prestashop 1.4 ou 1.5 :

  • Activer SSL + Forcer la redirection HTTPS dans .htaccess = TOO MANY REDIRECTS.
  • Activer SSL sans forcer la redirection = HTTPS fonctionnel dans le tunnel de paiement, mais pas dans le reste du site.
  • Désactiver SSL + Forcer la redirection HTTPS dans .htaccess = HTTPS fonctionnel dans la plupart des pages, sauf dans le tunnel de paiement (bloqué par les navigateurs récents).

Bref, aucune option n'est parfaite, et c'est bien énervant, n'est-ce-pas ? Nous allons donc prendre le problème à l'envers par rapport aux solutions inscrites dans les autres tutoriels. Nous constatons que si nous forçons la redirection HTTPS dans un fichier .htaccess, la totalité des pages s'affichent correctement et sont bien redirigées. Le seul souci est en fait la validation des étapes dans le tunnel de paiement (compte, livraison et paiement) qui d'un coup n'est pas protégée, voire forcée en HTTP, contrairement aux directives du .htaccess. Plutôt que de s'attaquer à l'ensemble des URL problématiques, il devient beaucoup plus simples de ne s'attaquer qu'aux URL du tunnel de paiement, bien moins nombreuses.

Tout d'abord, il est très fortement recommandé de décocher l'option "Rediriger automatiquement vers l'URL canonique" du menu "Préférences" > "SEO & URLs" dans notre cas, comme le montre la capture suivante (sinon, il faudrait modifier en profondeur la méthode canonicalRedirection() du fichier classes/controller/FrontController.php). Dans certains cas, décochez "URL simplifiée" peut aussi aider. Mon conseil est de désactiver la première des deux, d'appliquer les changements que nous verrons plus loin dans l'article, puis de venir enregistrer à nouveau cette section, sans forcément changer de valeurs (cela recréé le .htaccess comme il se doit). On peut également vider le cache Smarty si nécessaire afin que toutes les URL prennent la bonne forme (mais si ce n'est pas le cas, cela fonctionne tout de même, donc pas d'affolement).

Désactiver les redirections vers les canoniques dans Prestashop 1.5

Attaquons les classes de Prestashop...

Quand on observe le fichier template (.tpl) correspondant aux étapes du tunnel de conversion, on constate que Prestashop appelle toujours la méthode getPageLink(), c'est donc sur elle que nous allons agir dans un premier temps. Rappelons que nous avons bien désactivé l'option "Activer le SSL" dans le back-office, et qu'il faut donc forcer son activation "à la main" en remplaçant tout ce qui est en HTTP par HTTPS au sein des classes d'origine.

Dans nos modifications, certaines vont être purement fonctionnelles, et donc majeures pour faire tourner le tunnel de paiement en SSL forcé (donc sans blocage des navigateurs récents). D'autres changements ne vont que changer le "style" des URL, en les forçant en HTTPS plutôt qu'HTTP par défaut. Ces secondes modifications sont davantage cosmétiques mais il est recommandé de les appliquer aussi.

Premièrement, on modifie le fichier .htaccess pour forcer les redirections des pages HTTP vers HTTPS, comme l'indiquaient aussi les autres tutoriels. Il est recommandé de placer ce bloc tout en haut du fichier, car l'autre partie est générée par Prestashop lorsque l'on enregistre une modification dans "Préférences" > "SEO & URLs".

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>

Côté code, commençons par getPageLink(), située dans le fichier Link.php du dossiers "classes" à la racine de Prestashop. Il faut veiller à modifier la portion de code qui vérifie si le CMS doit afficher "HTTP" ou "HTTPS". Nous lui forçons à indiquer "HTTPS" donc il n'a plus trop le choix... :-)

public function getPageLink($controller, $ssl = false, $id_lang = null, $request = null, $request_url_encode = false, $id_shop = null) {
	$controller = Tools::strReplaceFirst('.php', '', $controller);

	if (!$id_lang)
		$id_lang = (int)Context::getContext()->language->id;

	if (!is_array($request))
	{
		// @FIXME html_entity_decode has been added due to '&amp;' => '%3B' ...
		$request = html_entity_decode($request);
		if ($request_url_encode)
			$request = urlencode($request);
		parse_str($request, $request);
	}

	if ($id_shop === null)
		$shop = Context::getContext()->shop;
	else
		$shop = new Shop($id_shop);

	$uri_path = Dispatcher::getInstance()->createUrl($controller, $id_lang, $request, false, '', $id_shop);

	// Fait fonctionner l'option SSL dans l'activer (force l'HTTPS)
	// $url = ($ssl && $this->ssl_enable) ? 'https://' : 'http://';
	$url = 'https://';
	$url .= $shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop).ltrim($uri_path, '/');

	return $url;
}
Modifications optionnelles en cas de bug restants...

Normalement tout devrait fonctionner pour votre boutique Prestashop sécurisée, mais si certains bugs persistent, il est fort à parier que vous deviez appliquer quelques modifications dans la classe Tools du fichier classes/Tools.php. Cette méthode est indiquée dans de nombreux forums et tutoriels (souvent de manière incomplète d'ailleurs) mais n'a pas été obligatoire dans mon cas par exemple. Toutefois, il faut bien avouer que cette classe regroupe des fonctions majeures comme celles sur la récupération du protocole d'origine, mais aussi celles pour les redirections en interne...

Ouvrez le fichier et lisez-le dans l'ordre, c'est le plus simple. Voyons quelques modifications que vous pourriez apporter :

  • méthode redirect() : ajoutez $url = str_replace('http://', 'https://', $url); juste avant le header(...) en fin de méthode.
  • méthode redirectLink() : même chose, ajoutez $url = str_replace('http://', 'https://', $url); juste avant le header(...) final.
  • méthode getShopProtocol() : remplacez la première ligne par $protocol = 'https://';.
  • méthode getProtocol() : remplacez l'unique ligne par return 'https://';.
  • méthode getHttpHost() : ajoutez $host = str_replace('http://', 'https://', $host); juste avant le return final.
  • méthode getShopDomain() : ajoutez $domain = str_replace('http://', 'https://', $domain); juste avant le return en fin de fonction.
  • méthode getShopDomainSsl() : faites exactement comme pour la méthode précédente, ajoutez $domain = str_replace('http://', 'https://', $domain); juste avant le return en fin de fonction.

Ce sont les modifications qui m'ont aidé au début avant de trouver la solution que je vous ai présentée précédemment. La grande différence est qu'il ne reste aucun bug apparent avec ma méthode. S'il vous en reste, il est fréquent que ce soit des modifications dans ces méthodes de la classe Tools que la réponse se trouve. Il n'est pas forcé d'appliquer tous les changements mais c'est recommandé si vous rencontrez toujours des problèmes...

Affichons toutes les URL de Prestashop 1.5 en HTTPS par défaut

Si vous faites ça, vous devriez déjà avoir quelque chose de fonctionnel, mais les URL seront toujours affichées en "HTTP" par défaut dans le code. Cela signifie que vous risquez d'obtenir des Mixed Content, peu appréciés par certains navigateurs. L'idéal est donc de modifier au maximum l'ensemble des URL de la boutique Prestashop pour qu'ils soient nativement en HTTPS (cela évite également des redirections en cascade via le .htaccess, et améliore donc quelque peu les performances).

Il va donc falloir modifier les URL de chaque type de ressource de Prestashop. Cela se fait aussi dans le fichier classes/Link.php. En effet, la classe contient plusieurs méthodes pour récupérer les formats des liens. Voici la liste de ces méthodes PHP :

  • getProductLink() : modifiez la ligne $url = 'http://'.$shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop); en ajoutant un "s" à "http://" en début de directive.
  • getCategoryLink() : modifiez la ligne $url = 'http://'.$shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop); en ajoutant un "s" à "http://" en début de directive.
  • getCMSCategoryLink() : modifiez la ligne $url = 'http://'.$shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop); en ajoutant un "s" à "http://" en début de directive.
  • getCMSLink() : modifiez $base au début de la fonction par $base = "https://";
  • getSupplierLink() : modifiez la ligne $url = 'http://'.$shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop); en ajoutant un "s" à "http://" en début de directive.
  • getManufacturerLink() : modifiez la ligne $url = 'http://'.$shop->domain.$shop->getBaseURI().$this->getLangLink($id_lang, null, $id_shop); en ajoutant un "s" à "http://" en début de directive.
  • getModuleLink() : modifiez $base au début de la fonction par $base = "https://";

Voilà, ces quelques petites modifications vont permettre de faire comprendre à Prestashop que vos URL de boutique doivent toutes être en HTTPS par défaut. Parfois, il reste du cache ou il faut générer à nouveau le fichier .htaccess pour que l'ensemble des modifications soient prises en compte, mais seules ces méthodes vont changer toutes les URL comme il se doit.

Conclusion

Vous devriez désormais avoir un Prestashop tout beau tout neuf, 100% fonctionnel en HTTPS, et sans problème de redirections en cascade, souvent lourdes de conséquences (en performances et en bugs potentiels). J'espère que ce tutoriel vous a plu si vous étiez dans la même galère que moi à ce sujet, et sinon, je vous recommande fortement de migrer à terme vers Prestashop 1.7 ou les versions à venir (mais cela oblige à refaire le thème, voire à racheter certains plugins devenus incompatibles) qui fonctionne avec PHP 7 et peut être totalement en HTTPS sans tout faire à la main...

Si certains bugs persistent, il peut être conseillé de vérifier la gestion du HTTPS dans la méthode init() du controller classes/controller/FrontController.php, notamment pour les trois variables suivantes : $protocol_link, $protocol_content et $useSSL (doit être sur "true").