Parse error: syntax error, unexpected token "public", expecting end of file in wp-content/themes/theme-repris/inc/class-widgets.php on line 1. L’erreur pointe la ligne 1 d’un fichier qui, ouvert dans l’éditeur de code, ne présente absolument rien d’anormal : la syntaxe PHP semble irréprochable, l’indentation est propre, aucune accolade ne manque à l’œil.
Symptôme : un fichier qui semble parfaitement valide
Ce cas s’est présenté lors de la reprise d’un thème client transféré par FTP depuis un ancien hébergement vers un nouveau serveur, sans passer par Git ni par un gestionnaire de versions. Le fichier fonctionnait parfaitement sur l’ancien hébergement, mais provoquait cette erreur bloquante immédiatement après le transfert vers le nouveau serveur, sans qu’aucune ligne de code n’ait été modifiée entre les deux.
Diagnostic : chercher ce qui ne se voit pas à l’œil
Face à une erreur de syntaxe sur un fichier qui semble correct visuellement, la première question à se poser n’est pas « qu’est-ce qui est mal écrit ? » mais « qu’est-ce qui a changé entre les deux environnements, sans être visible à l’œil nu ? ». Une inspection en hexadécimal des premiers octets du fichier a révélé la présence d’une marque d’ordre des octets (BOM, Byte Order Mark) au tout début du fichier :
hexdump -C wp-content/themes/theme-repris/inc/class-widgets.php | head -n 1
00000000 ef bb bf 3c 3f 70 68 70 0a 63 6c 61 73 73 20 57 |...<?php.class W|
Les trois octets ef bb bf avant même la balise <?php correspondent à l’encodage UTF-8 avec BOM. Le fichier d’origine était pourtant enregistré en UTF-8 sans BOM ; c’est le client FTP, configuré en mode de transfert texte plutôt que binaire, qui a réinterprété et réécrit l’encodage du fichier pendant le transfert, ajoutant ces octets invisibles avant la première ligne de code.

Pourquoi ces trois octets cassent tout
PHP interprète tout ce qui précède la première balise <?php comme du texte brut à afficher tel quel, pas comme du code à exécuter. Sur un fichier de classe qui ne devrait produire aucune sortie avant d’être inclus ailleurs, ces trois octets invisibles suffisent parfois à provoquer des avertissements « headers already sent » sur d’autres fichiers, et dans ce cas précis, une confusion du parseur PHP suffisamment sévère pour produire une erreur de syntaxe pointant vers la première ligne, alors même que le contenu réel du code n’a pas changé.
Correctif : re-sauvegarder sans BOM
La correction consiste à ouvrir le fichier dans un éditeur permettant de contrôler explicitement l’encodage de sauvegarde, et à le réenregistrer en UTF-8 sans BOM :
sed -i '1s/^\xEF\xBB\xBF//' wp-content/themes/theme-repris/inc/class-widgets.php
Cette commande supprime les trois octets BOM en début de fichier sans toucher au reste du contenu, ce qui restaure immédiatement un fichier interprétable normalement par PHP.
Prévention : bannir le mode texte FTP
La cause racine de cet incident n’est pas le fichier lui-même mais le mode de transfert utilisé. La plupart des clients FTP proposent un choix entre mode binaire et mode texte (ou ASCII), ce dernier étant censé « adapter » automatiquement les fins de ligne entre systèmes d’exploitation. Pour du code PHP, ce mode ne doit jamais être utilisé :
- Configurer le client FTP en transfert binaire systématique, quel que soit le type de fichier.
- Préférer, quand c’est possible, un déploiement via Git ou rsync plutôt qu’un simple transfert FTP manuel.
- Après tout transfert FTP d’un projet hérité sans gestionnaire de versions, faire tourner un contrôle de syntaxe sur l’ensemble des fichiers PHP avant de considérer la migration terminée.
find wp-content/themes/theme-repris -name "*.php" -exec php -l {} \;
Sur les reprises de thèmes sans historique Git, faire tourner systématiquement
php -lsur l’ensemble des fichiers juste après le transfert évite de découvrir ce genre d’incident en production, un par un.
En résumé
Une erreur de syntaxe sur un fichier visuellement irréprochable pointe presque toujours vers un problème d’encodage invisible plutôt qu’une véritable faute de code. Un transfert FTP en mode texte, une marque BOM ajoutée silencieusement, et un fichier parfaitement valide devient soudainement illisible pour PHP — un contrôle systématique en mode binaire évite ce piège une fois pour toutes.