Subversion Repository · 14 min read · Jan 19, 2026
Impostare un Repository Subversion Modulare Per Siti Web PHP-Driven
Impostare un Repository Subversion Modulare Per Siti Web PHP-Driven
Willem Bogaerts - Kratz Business Solutions
Abstract
Condividere codice tra progetti non è ancora una questione banale con subversion. Soprattutto se sei familiare con SourceSafe, scoprirai che subversion rende difficile condividere codice. Subversion sembra essere davvero ottimo nel creare un pasticcio di versioni e buono nel risolverne uno, ma il motivo per cui ho bisogno di controllo del codice sorgente è per prevenire tale pasticcio. Qui subversion può essere notevolmente migliorato, ma non è impossibile. Questo howto dimostrerà una configurazione delle directory che tiene conto del meccanismo di condivisione di subversion, così come di altri problemi che i repository portano.
Convenzione In Questo Howto
Vedrai
Si presume che tu sappia cos’è subversion, che conosci il suo utilizzo di base e che hai o puoi creare un repository.
Questo howto non ti fornisce “il migliore” modo per organizzare un repository, perché dipende dalle tue esigenze. Mira ad aiutarti mostrando alcune di quelle decisioni e come influenzano la struttura del repository.
Modo di Condivisione del Codice di Subversion
Le directory in una copia di lavoro possono contenere collegamenti ad altri repository definendo una proprietà svn:externals. Questo farà sì che la directory del repository collegato venga inclusa nella tua copia di lavoro, ma non diventerà parte del progetto stesso. Ciò significa che vedrai la directory con tutti i file nella tua copia di lavoro, ma non nel repository centrale. Puoi vedere la proprietà solo nel repository centrale.
Ci sono alcuni svantaggi a questo modo di condividere:
- Puoi fornire solo URL assoluti per i collegamenti, quindi migrare senza problemi un repository è quasi impossibile. Anche cambiare protocollo (da svn:// a https://, per esempio) porterà a copie di lavoro rotte e a molti problemi.
- Non puoi collegare file, solo directory. Questo avrà un grande impatto sull’organizzazione del codice.
Problemi di Directory PHP
Ci sono alcune cose da considerare quando si lavora con directory su un sito web, e in particolare PHP. Per motivi di sicurezza, non vogliamo mettere tutte le sorgenti in una directory accessibile da un browser. Gli unici file che metteremo lì sono file che devono essere chiamati da un browser. Chiamo questi file “file in esecuzione” rispetto ai “file di definizione” che contengono solo definizioni di classi o definizioni di funzioni. Mescolare codice in esecuzione e codice di definizione in un file non è generalmente una buona idea.
Inoltre, per motivi di sicurezza, molti siti hanno un’area riservata che contiene test unitari, pagine di log degli errori, o anche un intero sito di backoffice. Quest’area riservata è solitamente protetta da password dal server web.
Quindi un progetto contiene directory con file di definizione e una directory radice web (spesso www/ o htdocs/) che contiene file in esecuzione e, facoltativamente, un’area riservata.
PHP E Directory Relative
Purtroppo, PHP ha un modo molto controintuitivo di determinare la posizione di un file incluso. I comandi per l’inclusione di un file funzionano tutti rispetto al primo file chiamato, e non rispetto al file corrente. Per rendere le cose ancora peggiori, la posizione del file corrente viene utilizzata quando la posizione originale non porta a un file esistente.
Questo suona complicato, ed è, quindi ecco un esempio:
Supponiamo che tu chiami una pagina “index.php”. Questa pagina include una pagina “library/functions.php”. Questa a sua volta include “settings.php”. Ti aspetteresti che “settings.php” venga cercato nella directory library, ma non è così. Viene cercato nella stessa directory di “index.php”!
Come detto sopra, PHP continua a cercare nella directory prevista se il file non viene trovato. Quindi tutto sembra funzionare come ti aspetti, fino a quando non incontri file con lo stesso nome in directory diverse. Allora avrai davvero difficoltà a capire perché PHP “improvvisamente” sceglie il file dalla directory sbagliata.
Questo significa che non puoi includere in modo sicuro un altro file con percorsi relativi. Dobbiamo renderli assoluti con codice come:
require_once(dirname(__FILE__) . '/library/functions.php');Non dimenticare lo ‘/‘ all’inizio del percorso relativo, poiché la funzione dirname restituisce percorsi senza barre finali.
Organizzazione Del Nostro Repository
Ci sono alcune cose da considerare per il codice del progetto. Per lo sviluppo, è conveniente avere l’intero progetto controllato come un tutto. Ma per un server live, questo potrebbe non essere ciò che desideri. Potresti voler controllare il codice del database (script SQL) in una directory lontana dalle directory web, magari anche su un altro server. Potrebbero esserci parti del progetto che non vuoi affatto su un server, ma sono necessarie nello sviluppo, come i file di documentazione.
Inoltre, vogliamo un luogo centrale in cui memorizzare il codice condiviso. Potremmo teoricamente “prendere in prestito” codice da un altro progetto, ma sarebbe davvero difficile seguire quali progetti dipendono da quali altri progetti. Invece, sposteremo qualsiasi codice standard in una posizione centrale.
Directory Radice
La posizione centrale contenente tutto il codice standard sarà “
Rami E Tag
È buona prassi in un repository subversion mantenere il tuo codice in un ramo chiamato “trunk” e creare altri rami allo stesso livello se necessario. Anche se non vuoi ancora alcun ramo, crea una directory “trunk” direttamente sotto un progetto. Trunk è il ramo attivo.
Pensa a questo. Quando colleghiamo al trunk di una libreria standard, colleghiamo al ramo attivo. Questo significa che tutte le correzioni di errori nella libreria collegata verranno aggiornate ogni volta che aggiorniamo una copia di lavoro. Ma se introduciamo un errore, questo verrà aggiornato anche nelle nostre copie di lavoro. Anche quella su un server web live! Potresti voler collegarti a un ramo più o meno stabile invece, ma correggere errori richiederà un po’ più di overhead.
Qualunque collegamento tu scelga, è bene sapere che puoi sempre cambiare in seguito.
Cosa C’è In Un Componente O Progetto
Ci sono molte cose che vogliamo mettere in un repository, e non vogliamo tutto nello stesso posto sul nostro server web. Alcune cose è meglio non metterle affatto su un server web o potrebbero essere controllate su un server diverso, come un server di database.
Nota che la configurazione di una copia di lavoro su una macchina di sviluppo differisce da quella su un server. Su una macchina di sviluppo, probabilmente avrai una directory radice centrale per tutti i tuoi progetti. Questa directory è quindi configurata come accessibile tramite il tuo server web localhost, così non devi riconfigurare il tuo server per ogni progetto su cui stai lavorando. Su un server live, le cose devono essere comunque configurate e considerazioni di sicurezza ci portano a controllare solo quei file che sono necessari e nient’altro. Per cominciare, creiamo le seguenti directory in ogni componente (se necessario):
documentation/Input del cliente, schemi di database e oggetti, ecc. Non è necessario mettere questo su un server web, ma è molto utile per gli sviluppatori.sql/Script di creazione, aggiornamento e conversione del database. per il checkout sul server di database.code/Il codice dell’applicazione effettivatest/Test unitari
Queste directory appaiono grossomodo le stesse nei progetti, con la differenza che i test unitari dovrebbero essere eseguibili e sono quindi parte della sezione codice. Se non vuoi che i test unitari siano presenti su un server live, puoi tenerli separati. Per i progetti, la mia configurazione sarà:
documentation/Come sopra. Contiene anche riferimenti dai componenti utilizzati.database/Contiene script di creazione del database e riferimenti dalle directory sql dei componenti utilizzati.web/Il codice dell’applicazione definente.web/htdocs/La radice del sito con il codice dell’applicazione in esecuzione effettivo, pagine HTML e altri contenuti web, come fogli di stile e immagini.web/htdocs/restricted/Area riservata.web/test/Test unitari. Contiene riferimenti dai test dei componenti utilizzati.selenium/Test funzionali (vedi
Codice In Esecuzione E Codice Di Definizione (Ancora)
Potremmo mettere codice in esecuzione e codice di definizione in directory separate, in modo da poter controllare il codice in esecuzione in una directory separata all’interno della radice web. Tuttavia, questo significa che la sottodirectory contenente quel codice diventerebbe parte dell’URL (come www.example.com/restricted/errorhandling/viewerrorlog.php), e questo potrebbe non essere ciò che desideri (potresti voler www.example.com/restricted/viewerrorlog.php). C’è una soluzione a questo. Possiamo mettere i file in esecuzione in un luogo non accessibile e mettere una sorta di proxy in un luogo accessibile. Questo proxy è un file PHP con nient’altro che un’istruzione include o require che punta al file nella posizione non accessibile:
/htdocs/restricted/viewerrorlog.php
// È un proxy che punta a /errorhandling/viewerrorlog.php, che non può essere chiamato direttamente da un browser.
// (perché è al di fuori della radice web)
require(dirname(__FILE__) . '/../../errorhandling/viewerrorlog.php');
?> La directory errorhandling è quindi condivisa dalla libreria standard e contiene file di classe “definenti” per gestire gli errori e un file “in esecuzione” per visualizzarli.
Impostazioni Dipendenti Dalla Macchina
I file di impostazione sono un po’ insoliti in un repository. Vuoi averli in un repository, ma non vuoi che vengano aggiornati automaticamente. Uso un metodo intermedio per i miei file di impostazione: creo un file chiamato settings_example.php nella directory delle impostazioni. Questo file contiene tutte le impostazioni con commenti su come impostarle per diverse macchine. Contiene anche un commento che dice che devi copiarlo in un file chiamato “settings.php”
Faccio solo riferimento a settings.php da altri file, e imposto una proprietà svn:ignore con il valore di “settings.php” sulla directory delle impostazioni. Questo significa che una copia di lavoro non funzionerà “out of the box”, ma non lo farà comunque a causa della dipendenza dalle impostazioni dipendenti dalla macchina. La proprietà svn:ignore impedisce che le impostazioni di macchine diverse sovrascrivano le tue durante un aggiornamento.
Metterlo In Pratica
Un esempio. Supponiamo di avere un progetto che deve inviare email e creare file PDF. Abbiamo deciso di utilizzare PHPMailer di PEAR e le librerie FPDF. Per evitare di imporre restrizioni speciali nella configurazione di PHP, scarichiamo semplicemente PHPMailer e non utilizziamo il metodo “pear install” per installarlo.
Inoltre, questo progetto avrà una gestione degli errori standard e una classe database standard. Per semplicità, suppongo che tu parta da un repository vuoto.
Creare Le Directory Necessarie
Per prima cosa, crea le directory radice descritte sopra:
Ci occuperemo prima delle librerie esterne. Scarica e decomprimi PHPMailer e FPDF, e importali in
Successivamente, creiamo un progetto su cui lavorare. Questo progetto è per il cliente “CustomerInc” e il progetto si chiama “SamplePrj”. Sono sicuro che puoi trovare nomi migliori per i tuoi progetti. Quindi creiamo il percorso completo di
Sotto la directory web, ho creato una radice web (htdocs) e una directory per file php specifici del progetto generico.
Creare Le Condivisioni
Fino ad ora, ho fatto tutto direttamente sul repository. Ma per condividere codice, dobbiamo prima fare una copia di lavoro. Quindi facciamolo.
Poiché il nostro server web localhost deve essere in grado di raggiungere tutto il nostro codice di progetto, faccio la mia copia di lavoro su una cartella radice del mio filesystem (/projects/
Nella nostra copia di lavoro, abbiamo la directory web, dove si trova la directory htdocs e dove vogliamo i collegamenti a FPDF e PHPMailer. Per creare quei collegamenti, aggiungi una proprietà subversion svn:external alla directory web con il seguente valore:
fpdf /external/fpdf/trunk/code
phpmailer /external/phpmailer/trunk/code (sì, il valore è composto da 2 righe) e poi aggiorna la tua copia di lavoro. Dovresti ora ottenere due directory extra con il tuo aggiornamento, come mostrato in questo screenshot di una copia di lavoro del nostro progetto.
Nota: ho creato i collegamenti al trunk. Potresti collegarti a un ramo invece o collegarti a un numero di revisione specifico. Ho creato solo riferimenti esterni alle sezioni di codice. Probabilmente vorresti creare riferimenti esterni alla documentazione delle librerie esterne anche.
Spostare Codice Utile Nella Libreria Standard
Man mano che i tuoi progetti maturano, sviluppi sempre più codice che sarebbe utile in altri progetti. Nel nostro caso, diciamo che abbiamo sviluppato un pacchetto di gestione degli errori e una classe database. Ovviamente, il primo passo è rimuovere eventuali dipendenze di progetto da questo codice. Metti il codice da condividere (chiamiamolo un pacchetto) in una directory separata, poiché deve essere in una directory separata quando viene condiviso dalla libreria standard. Quindi ci assicuriamo che il codice generico di gestione degli errori sia in una directory errorhandling e la classe database sia in una directory database, entrambe direttamente sotto la directory web.
Puoi usare i comandi svn mkdir e svn move o qualsiasi client grafico di subversion per spostare il pacchetto nel tuo progetto in
Se aggiorni le tue copie di lavoro dopo ogni modifica sul server, nulla può andare storto. Il problema sorge quando hai una copia di lavoro che ha ancora il pacchetto nella posizione originale del progetto e vuoi aggiornare a uno stato in cui quella stessa directory ora proviene da un riferimento svn:externals. Se provi a farlo, riceverai un errore che dice che la directory di destinazione per quel riferimento esterno esiste già, quindi il riferimento esterno non può essere creato. Questo è facilmente risolvibile rimuovendo manualmente quella directory prima di aggiornare quella copia di lavoro.
Sposta eventuali test unitari, documentazione, script SQL, ecc. in modo simile nella libreria standard.
Aggiornare Il Server Live
Quando più di una persona ha accesso al server web o al server di database, è meglio utilizzare un account per tutti loro. Questo assicura che le directory .svn non soffrano di impostazioni di account e diritti utente in conflitto. Inoltre, puoi negare a quell’account i permessi di scrittura sul repository, in modo che un server web compromesso non possa facilmente commettere cose brutte.
Su un server web Linux, i seguenti diritti hanno senso: lettura e scrittura per l’utente che aggiorna la copia di lavoro “live”, diritti di lettura per il gruppo (che è il gruppo del server web) e nessun diritto per gli altri. Se imposti il bit SGID sulle directory, tutti i file aggiunti saranno anche accessibili al server web. Puoi impostare il bit SGID con chmod g+s
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.cssCodice Database Modulare
Abbiamo già discusso di come funzionano gli include in PHP, ma come includiamo file in SQL? Dobbiamo essere in grado di includere file diversi da directory diverse nel codice SQL, poiché abbiamo organizzato il nostro repository in questo modo. Se condividiamo codice PHP, dovremmo condividere anche il corrispondente codice SQL. Ho scritto un piccolo script PHP e un piccolo script python per farlo. Puoi trovarli su http://www.w-p.dds.nl/sqlincludeparser_php.txt (PHP) e http://www.w-p.dds.nl/sqlincludeparser_py.txt (Python). Questi script ti consentono di definire istruzioni include in un file base della forma:
CREATE DATABASE IF NOT EXISTS someDatabase;
USE someDatabase;
-- @include(errorhandling/errortables.sql) # (re)crea tabelle utilizzate dal pacchetto di gestione degli errori
DROP TABLE IF EXISTS someTable;
CREATE TABLE someTable
(someID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
...ecc.Se rendi ogni file incluso e il file base ripetibile, puoi usarlo per tornare a uno stato pulito più e più volte, il che può essere molto utile per testare e sviluppare. Per usarlo, basta canalizzare l’output del mio script al client della riga di comando sql:
sqlincludeparser.py | mysql -u -p [] Ricevi i nuovi post nella tua casella di posta.
Nessuno spam. Disiscriviti in qualsiasi momento.