Subversion PHP · 16 min read · Jan 19, 2026

Configuration d'un dépôt Subversion modulaire pour des sites Web alimentés par PHP

Configuration d’un dépôt Subversion modulaire pour des sites Web alimentés par PHP

Willem Bogaerts - Kratz Business Solutions

Résumé

Partager du code entre des projets n’est toujours pas une affaire triviale avec Subversion. Surtout si vous êtes familier avec SourceSafe, vous constaterez que Subversion rend difficile le partage de code. Subversion semble vraiment excellent pour créer un désordre de version et bon pour en résoudre un, mais la raison pour laquelle j’ai besoin d’un contrôle de code source est de prévenir un tel désordre. C’est là que Subversion peut être grandement amélioré, mais ce n’est pas impossible. Ce guide montrera une configuration de répertoire qui prend en compte le mécanisme de partage de Subversion, ainsi que d’autres problèmes que les dépôts apportent.

Convention dans ce guide

Vous verrez à de nombreux endroits. Remplacez cela par la racine de votre dépôt. La racine de votre dépôt est une URL qui commence généralement par https://, file:/// ou svn://.
Il est supposé que vous savez ce qu’est Subversion, que vous connaissez son utilisation de base et que vous avez ou pouvez créer un dépôt.
Ce guide ne vous donne pas “la meilleure” façon d’organiser un dépôt, car cela dépend de vos besoins. Il vise à aider en montrant certaines de ces décisions et comment elles affectent la structure du dépôt.

La façon dont Subversion partage le code

Les répertoires dans une copie de travail peuvent contenir des liens vers d’autres dépôts en définissant une propriété svn:externals. Cela fera en sorte que le répertoire du dépôt lié soit inclus dans votre copie de travail, mais ne le rendra pas partie intégrante du projet lui-même. Cela signifie que vous verrez le répertoire avec tous les fichiers dans votre copie de travail, mais pas dans le dépôt central. Vous ne pouvez voir la propriété que dans le dépôt central.

Il y a quelques inconvénients à cette façon de partager :

  • Vous ne pouvez donner que des URL absolues pour les liens, donc migrer un dépôt sans heurts est presque impossible. Même changer de protocoles (svn:// vers https:// par exemple) entraînera des copies de travail cassées et beaucoup de problèmes.
  • Vous ne pouvez pas lier des fichiers, seulement des répertoires. Cela aura un grand impact sur l’organisation du code.

Problèmes de répertoire PHP

Il y a quelques éléments à considérer lorsque vous travaillez avec des répertoires sur un site Web, et en particulier PHP. Par mesure de sécurité, nous ne voulons pas mettre toutes les sources dans un répertoire accessible depuis un navigateur. Les seuls fichiers que nous mettrons là sont des fichiers qui doivent être appelés par un navigateur. J’appelle ces fichiers des fichiers “exécutables” par opposition aux fichiers “définissant” qui n’ont que des définitions de classe ou des définitions de fonction à l’intérieur. Mélanger du code exécutable et du code définissant dans un même fichier n’est généralement pas une bonne idée.

Également par mesure de sécurité, de nombreux sites ont une zone restreinte qui contient des tests unitaires, des pages de journaux d’erreurs, ou même un site backoffice complet. Cette zone restreinte est généralement protégée par mot de passe par le serveur Web.

Ainsi, un projet contient des répertoires avec des fichiers définissant et un répertoire racine Web (souvent www/ ou htdocs/) qui contient des fichiers exécutables et éventuellement une zone restreinte.

PHP et répertoires relatifs

Hélas, PHP a une façon très contre-intuitive de déterminer l’emplacement d’un fichier inclus. Les commandes pour l’inclusion d’un fichier fonctionnent toutes par rapport au premier fichier appelé, et non par rapport au fichier actuel. Pour aggraver les choses, l’emplacement du fichier actuel est utilisé lorsque l’emplacement d’origine ne mène pas à un fichier existant.

Cela semble compliqué, et c’est le cas, alors voici un exemple :

Supposons que vous appeliez une page “index.php”. Cette page inclut une page “library/functions.php”. Celle-ci inclut à son tour “settings.php”. Vous vous attendriez à ce que “settings.php” soit recherché dans le répertoire de la bibliothèque, mais ce n’est pas le cas. Il est recherché dans le même répertoire que “index.php” !

Comme dit ci-dessus, PHP continue de chercher dans le répertoire attendu si le fichier n’est pas trouvé. Donc tout semble fonctionner comme vous l’attendez, jusqu’à ce que vous rencontriez des fichiers avec le même nom dans différents répertoires. Vous aurez alors beaucoup de mal à comprendre pourquoi PHP “choisit soudainement” le fichier du mauvais répertoire.

Cela signifie que vous ne pouvez pas inclure en toute sécurité un autre fichier avec des chemins relatifs. Nous devons les rendre absolus avec du code comme :

require_once(dirname(__FILE__) . '/library/functions.php');

N’oubliez pas le ‘/‘ au début du chemin relatif, car la fonction dirname renvoie des chemins sans barres obliques finales.

Organisation de notre dépôt

Il y a quelques éléments à considérer pour le code du projet. Pour le développement, il est pratique d’avoir l’ensemble du projet vérifié dans son intégralité. Mais pour un serveur en direct, ce n’est peut-être pas ce que vous voulez. Vous voudrez peut-être vérifier le code de la base de données (scripts SQL) dans un répertoire éloigné des répertoires Web, peut-être même sur un autre serveur. Il peut y avoir des parties du projet que vous ne souhaitez pas du tout sur un serveur, mais qui sont nécessaires en développement, comme des fichiers de documentation.

De plus, nous voulons un endroit central pour stocker le code partagé. Nous pourrions théoriquement “emprunter” du code d’un autre projet, mais il serait vraiment difficile de suivre quels projets dépendent de quels autres projets. Au lieu de cela, nous déplacerons tout code standard vers un emplacement central.

Répertoires racines

L’emplacement central contenant tout le code standard sera “/standard/“. Ce répertoire sera bien sûr subdivisé en bibliothèques standard. Les projets seront dans le dossier “/projects/“, qui peut être subdivisé par client et projet, par exemple. Le code provenant de l’extérieur, comme les bibliothèques téléchargées telles que PHPMailer ou FPDF, sera placé dans “/external/“.

Branches et tags

Il est de bonne pratique dans un dépôt Subversion de garder votre code dans une branche appelée “trunk” et de créer d’autres branches au même niveau si nécessaire. Même si vous ne voulez pas encore de branches, créez un répertoire “trunk” directement sous un projet. Trunk est la branche active.

Réfléchissez à cela. Lorsque nous lierons au trunk d’une bibliothèque standard, nous lierons à la branche active. Cela signifie que toutes les corrections d’erreurs dans la bibliothèque liée seront mises à jour chaque fois que nous mettrons à jour une copie de travail. Mais si nous introduisons une erreur, cela sera également mis à jour dans nos copies de travail. Même celle sur un serveur Web en direct ! Vous voudrez peut-être lier à une branche plus ou moins stable à la place, mais corriger des erreurs nécessitera un peu plus de surcharge.

Quel que soit le lien que vous choisissez, il est bon de savoir que vous pouvez toujours changer plus tard.

Qu’est-ce qu’un composant ou un projet

Il y a beaucoup de choses que nous voulons mettre dans un dépôt, et nous ne voulons pas que tout soit au même endroit sur notre serveur Web. Certaines choses sont mieux à ne pas mettre du tout sur un serveur Web ou peuvent être vérifiées sur un serveur différent, comme un serveur de base de données.

Notez que la configuration d’une copie de travail sur une machine de développement diffère de celle sur un serveur. Sur une machine de développement, vous aurez probablement un répertoire racine central pour tous vos projets. Ce répertoire est ensuite configuré comme accessible via votre serveur Web localhost, afin que vous n’ayez pas à reconfigurer votre serveur pour chaque projet sur lequel vous travaillez. Sur un serveur en direct, les choses doivent être configurées de toute façon et les considérations de sécurité nous obligent à ne vérifier que les fichiers nécessaires et rien de plus. Pour commencer, nous créons les répertoires suivants dans chaque composant (si nécessaire) :

documentation/Entrée client, schémas de base de données et d’objets, etc. Pas besoin de mettre cela sur un serveur Web, mais c’est très utile pour les développeurs.sql/scripts de création, de mise à jour et de conversion de base de données. pour vérification sur le serveur de base de données.code/Le code d’application réeltest/Tests unitaires

Ces répertoires apparaissent à peu près de la même manière dans les projets, avec la différence que les tests unitaires doivent être exécutables et font donc partie de la section code. Si vous ne voulez pas que les tests unitaires soient présents sur un serveur en direct, vous pouvez les garder séparés. Pour les projets, ma configuration sera :

documentation/Comme ci-dessus. Contient également des références des composants utilisés.base de données/Contient des scripts de création de base de données et des références des directoires sql des composants utilisés.web/Le code d’application définissant.web/htdocs/La racine du site avec le code d’application réel, les pages HTML et d’autres contenus Web, comme des feuilles de style et des images.web/htdocs/restricted/Zone restreinte.web/test/Tests unitaires. Contient des références des tests des composants utilisés.selenium/Tests fonctionnels (voir

http://selenium.openqa.org/).

Code exécutant et définissant (encore)

Nous pourrions mettre le code exécutant et le code définissant dans des répertoires séparés, afin que nous puissions vérifier le code exécutant dans un répertoire séparé à l’intérieur de la racine Web. Cependant, cela signifie que le sous-répertoire contenant ce code deviendrait partie de l’URL (comme www.example.com/restricted/errorhandling/viewerrorlog.php), et cela peut ne pas être ce que vous voulez (vous voudrez peut-être www.example.com/restricted/viewerrorlog.php). Il y a une solution à cela. Nous pouvons mettre les fichiers exécutables dans un endroit non accessible et mettre une sorte de proxy dans un endroit accessible. Ce proxy est un fichier PHP avec rien d’autre qu’une instruction include ou require qui pointe vers le fichier dans l’emplacement non accessible :

/htdocs/restricted/viewerrorlog.php
// C'est un proxy qui pointe vers /errorhandling/viewerrorlog.php, qui ne peut pas être appelé directement par un navigateur.
// (car il est en dehors de la racine Web)
require(dirname(__FILE__) . '/../../errorhandling/viewerrorlog.php');
?>

Le répertoire errorhandling est ensuite partagé depuis la bibliothèque standard et contient des fichiers de classe “définissant” pour gérer les erreurs et un fichier “exécutant” pour les afficher.

Paramètres dépendants de la machine

Les fichiers de paramètres sont un peu inhabituels dans un dépôt. Vous voulez les avoir dans un dépôt, mais vous ne voulez pas qu’ils soient mis à jour automatiquement. J’utilise une méthode intermédiaire pour mes fichiers de paramètres : je crée un fichier appelé settings_example.php dans le répertoire des paramètres. Ce fichier contient tous les paramètres avec des commentaires sur la façon de les définir pour différentes machines. Il contient également un commentaire qui dit que vous devez le copier dans un fichier appelé “settings.php”.

Je ne fais référence qu’à settings.php depuis d’autres fichiers, et je définis une propriété svn:ignore avec la valeur “settings.php” sur le répertoire des paramètres. Cela signifie qu’une copie de travail ne fonctionnera pas “hors de la boîte”, mais cela ne fonctionnera de toute façon pas en raison de la dépendance aux paramètres dépendants de la machine. La propriété svn:ignore empêche les paramètres de différentes machines d’écraser les vôtres lors d’une mise à jour.

Mettre en pratique

Un exemple. Disons que nous avons un projet qui doit envoyer des e-mails et créer des fichiers PDF. Nous avons décidé d’utiliser PHPMailer de PEAR et les bibliothèques FPDF. Pour éviter d’imposer des restrictions spéciales dans la configuration de PHP, nous téléchargeons simplement PHPMailer et n’utilisons pas la méthode “pear install” pour l’installer.

De plus, ce projet aura une gestion des erreurs standard et une classe de base de données standard. Pour des raisons de simplicité, je suppose que vous commencez avec un dépôt vide.

Création des répertoires nécessaires

Tout d’abord, créez les répertoires racines décrits ci-dessus : /external/, /standard/ et /projects/. Je recommande d’utiliser un frontend graphique pour Subversion, tel que TortoiseSVN ou RapidSVN.

Nous allons d’abord nous occuper des bibliothèques externes. Téléchargez et décompressez PHPMailer et FPDF, et importez-les dans /external/phpmailer/trunk/ et /external/fpdf/trunk/ respectivement. Si vous le souhaitez, vous pouvez créer des branches “firstdownload” à partir des deux.

Ensuite, nous créons un projet sur lequel travailler. Ce projet est pour le client “CustomerInc” et le projet est nommé “SamplePrj”. Je suis sûr que vous pouvez trouver de meilleurs noms pour vos projets. Donc, nous créons le chemin complet de /projects/CustomerInc/SamplePrj/trunk/. Le “trunk” est la branche principale : vous pouvez travailler dans d’autres branches (de développement), mais elles sont finalement fusionnées dans le trunk. Si vous travaillez sur le trunk (et pourquoi ne le feriez-vous pas si c’est un nouveau projet), ce répertoire est le répertoire à vérifier comme copie de travail. Mais attendons un peu. Sous le trunk, nous créons des répertoires “purpose” pour le code Web (php, html, etc.), le code de base de données et la documentation.
Sous le répertoire Web, j’ai créé une racine Web (htdocs) et un répertoire pour des fichiers php spécifiques au projet génériques.

Création des partages

Jusqu’à présent, j’ai tout fait directement sur le dépôt. Mais pour partager du code, nous devons d’abord créer une copie de travail. Alors faisons cela.

Parce que notre serveur Web localhost doit pouvoir atteindre tout notre code de projet, je fais ma copie de travail dans un dossier racine de mon système de fichiers (/projects//) ou disque dur (C:\projects\\). Sinon, le serveur Web doit avoir des droits d’accès dans le répertoire personnel de tous les utilisateurs qui utilisent Subversion. En utilisant un dossier racine, vous pouvez vous assurer que le serveur Web peut y accéder tous, et vous pouvez même séparer les répertoires pour différents utilisateurs. Pour les systèmes basés sur Unix, tous les utilisateurs de Subversion doivent être membres du groupe de votre serveur Web, et le répertoire total des projets doit être au moins lisible par le groupe. Au moins les choses Web, c’est-à-dire.

Dans notre copie de travail, nous avons le répertoire Web, où se trouve le répertoire htdocs et où nous voulons les liens vers FPDF et PHPMailer. Pour créer ces liens, ajoutez une propriété Subversion svn:external au répertoire Web avec la valeur suivante :

fpdf /external/fpdf/trunk/code
phpmailer /external/phpmailer/trunk/code

(oui, la valeur se compose de 2 lignes) et mettez ensuite à jour votre copie de travail. Vous devriez maintenant obtenir deux répertoires supplémentaires avec votre mise à jour, comme le montre cette capture d’écran d’une copie de travail de notre projet.

Remarque : J’ai créé les liens vers le trunk. Vous pouvez lier à une branche à la place ou lier à un numéro de révision spécifique. J’ai créé uniquement des références externes aux sections de code. Vous voudrez probablement créer des références externes à la documentation des bibliothèques externes également.

Déplacer le code utile vers la bibliothèque standard

À mesure que vos projets mûrissent, vous développez de plus en plus de code qui serait utile dans d’autres projets. Dans notre cas, disons que nous avons développé un package de gestion des erreurs et une classe de base de données. Bien sûr, la première étape consiste à supprimer toute dépendance de projet de ce code. Mettez le code à partager (appelons-le un package) dans un répertoire séparé, car il doit être dans un répertoire séparé lorsqu’il est partagé depuis la bibliothèque standard. Assurons-nous que le code de gestion des erreurs générique se trouve dans un répertoire errorhandling et que la classe de base de données se trouve dans un répertoire database, tous deux directement sous le répertoire Web.

Vous pouvez utiliser les commandes svn mkdir et svn move ou tout client graphique Subversion pour déplacer le package dans votre projet vers /standard//trunk/code. N’oubliez pas de mettre à jour votre copie de travail de développement après cela (vous verrez le répertoire du package disparaître), puis ajoutez deux lignes à la propriété svn:external (sous la forme /standard//trunk/code), mettez à jour (pour récupérer le répertoire, maintenant depuis la bibliothèque standard) et validez le changement de propriété. La plupart des problèmes se trouvent dans la mise à jour de vos copies de travail, surtout si cette copie de travail est un site Web en direct pour lequel vous souhaitez le moins de temps d’arrêt possible.
Si vous mettez à jour vos copies de travail après chaque changement sur le serveur, rien ne peut mal tourner. Le problème survient lorsque vous avez une copie de travail qui a encore le package à l’emplacement de projet d’origine et que vous souhaitez mettre à jour vers un état où ce même répertoire provient maintenant d’une référence svn:externals. Si vous essayez cela, vous obtiendrez une erreur disant que le répertoire cible pour cette référence externe existe déjà, donc la référence externe ne peut pas être créée. Cela se résout facilement en supprimant ce répertoire manuellement avant de mettre à jour cette copie de travail.

Déplacez tous les tests unitaires, la documentation, les scripts SQL, etc. de manière similaire vers la bibliothèque standard.

Mise à jour du serveur en direct

Lorsque plus d’une personne a accès au serveur Web ou de base de données, il est préférable d’utiliser un compte pour tous. Cela garantit que les répertoires .svn ne souffrent pas de conflits de paramètres de compte et de droits d’utilisateur. De plus, vous pouvez refuser à ce compte des permissions d’écriture sur le dépôt, de sorte qu’un serveur Web compromis ne puisse pas facilement commettre des choses désagréables.

Sur un serveur Web Linux, les droits suivants ont du sens : lecture et écriture pour l’utilisateur qui met à jour la copie de travail “en direct”, droits de lecture pour le groupe (qui est le groupe du serveur Web) et aucun droit pour les autres. Si vous définissez le bit SGID sur les répertoires, tous les fichiers ajoutés seront également accessibles au serveur Web. Vous pouvez définir le bit SGID avec chmod g+s . Envisagez de définir le umask à 0027 pour définir les permissions correctement pour les fichiers ajoutés également. Un répertoire htdocs fraîchement ajouté peut alors ressembler à :

drwxr-s--- 9 webdev abyssd 4096 2007-09-08 12:42 restricted/  
-rw-r----- 1 webdev abyssd 441 2007-09-08 12:42 index.php  
-rw-r----- 1 webdev abyssd 2954 2007-09-08 12:42 main.css

Code de base de données modulaire

Nous avons déjà discuté de la façon dont les inclusions fonctionnent en PHP, mais comment incluons-nous des fichiers dans SQL ? Nous devons être capables d’inclure différents fichiers de différents répertoires dans le code SQL, car nous avons organisé notre dépôt de cette manière. Si nous partageons du code PHP, nous devrions également partager le code SQL correspondant. J’ai écrit un petit script PHP et un petit script Python pour faire cela. Vous pouvez les trouver à http://www.w-p.dds.nl/sqlincludeparser_php.txt (PHP) et http://www.w-p.dds.nl/sqlincludeparser_py.txt (Python). Ces scripts vous permettent de définir des instructions d’inclusion dans un fichier de base sous la forme :

CREATE DATABASE IF NOT EXISTS someDatabase;
USE someDatabase;
-- @include(errorhandling/errortables.sql) # (re)crée les tables utilisées par le package de gestion des erreurs
DROP TABLE IF EXISTS someTable;
CREATE TABLE someTable
      (someID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
...etc.

Si vous rendez chaque fichier inclus et le fichier de base répétable, vous pouvez l’utiliser pour revenir à un état propre encore et encore, ce qui peut être très utile pour les tests et le développement. Pour l’utiliser, il suffit de rediriger la sortie de mon script vers le client de ligne de commande SQL :

sqlincludeparser.py  | mysql -u  -p []
Share: X/Twitter LinkedIn

Recevez de nouveaux articles dans votre boîte de réception.

Aucun spam. Désabonnez-vous à tout moment.