source: spip-zone/_plugins_/fabrique/trunk/inc/fdiff.php @ 70033

Last change on this file since 70033 was 70033, checked in by marcimat@…, 8 years ago

PHPDoc complet de la fabrique

File size: 9.9 KB
Line 
1<?php
2
3/**
4 * Ce fichier contient des fonctions utiles pour
5 * la génération d'un diff (unix/windows) entre 2 dossiers.
6 *
7 * Nécessite la commande `exec()`
8 *
9 * Ces fonctions sont encapsulées dans une classe "Fdiff"
10 *
11 * Cette API est perfectible...
12 *
13 * @author Marcimat
14 * @author Julien Lanfray (le fonctionnement sous windows)
15 * @package SPIP\Fabrique\Fdiff
16**/
17
18
19
20/**
21 * Encapsule les fonctions permettant de réaliser un diff entre 2 dossiers
22 *
23 * @example
24 *     ```
25 *     $fdiff = new Fdiff($ancien_repertoire, $nouveau_repertoire);
26 *     ```
27**/
28Class Fdiff {
29
30        /**
31         * Dossier source de la comparaison (l'ancien)
32         * @var string */
33        private $dossier1 = "";
34
35        /**
36         * Dossier destination de la comparaison (le nouveau)
37         * @var string */
38        private $dossier2 = "";
39
40        /**
41         * Fichiers ignorés
42         * @var array */
43        private $ignorer = array(".", "..");
44
45        /**
46         * Fichiers ignorés (par extension)
47         * @var array */
48        private $ignorer_extensions = array("svn", "db");
49
50        /**
51         * Commande diff/fc non realisée sur ces fichiers (par extension)
52         * @var array */
53        private $ignorer_extensions_complementaires = array("png", "jpg", "jpeg", "gif");
54
55
56        /**
57         * Constructeur
58         *
59         * @param string $dossier1
60         *     Chemin du repertoire source de la comparaison (l'ancien)
61         * @param string $dossier2
62         *     Chemin du repertoire destination de la comparaison (le nouveau)
63         *
64        **/
65        public function __construct($dossier1, $dossier2) {
66                $this->dossier1 = $dossier1;
67                $this->dossier2 = $dossier2;
68        }
69
70
71
72        /**
73         * Ajoute des noms de fichiers/dossiers à la liste d'exclusion.
74         *
75         * Ces fichiers ne seront pas du tout traités.
76         *
77         * @param array $tab
78         *     tableau de nom de fichiers/dossiers
79         *
80        **/
81        public function add_ignorer($tab){
82                if (!$tab) return;
83
84                if (!is_array($tab)) {
85                        $tab = array($tab);
86                }
87
88                $this->ignorer = array_merge($this->ignorer, $tab);
89        }
90
91
92        /**
93         * Ajoute des extensions de fichiers/dossiers à la liste d'exclusion.
94         *
95         * Les fichiers portants ces extensions ne seront pas du tout traités.
96         *
97         * @param array $tab
98         *     tableau d'extensions - ex: array('dat')
99         *
100        **/
101        public function add_ignorer_extensions($tab){
102                if (!$tab) return;
103
104                if (!is_array($tab)) {
105                        $tab = array($tab);
106                }
107
108                $this->ignorer_extensions = array_merge($this->ignorer_extensions, $tab);
109        }
110
111
112
113        /**
114         * Ajoute des extensions de fichiers/dossiers à la liste d'exclusion.
115         *
116         * Les fichiers portants ces extensions peuvent être pris en compte
117         * dans le calcul des ajouts/suppressions
118         * mais aucune comparaison ne sera fait sur ces fichiers.
119         *
120         * @param array $tab
121         *     tableau d'extensions - ex: array('dat')
122         *
123        **/
124        public function add_ignorer_extensions_complementaires($tab){
125                if (!$tab) return;
126
127                if (!is_array($tab)) {
128                        $tab = array($tab);
129                }
130
131                $this->ignorer_extensions_complementaires = array_merge($this->ignorer_extensions_complementaires, $tab);
132        }
133
134
135        /**
136         * Construit une expression regulière reconnaissant des extensions de fichiers
137         *
138         * @param array $tab
139         *    La liste des extensions de fichiers
140         * @return string
141         *    Expression reguliere. ex: `"/(\.svn|\.db)$/i"`
142         *
143        **/
144        private function ereg_filtre_extensions($tab){
145                if (!is_array($tab)) {
146                        $tab = array($tab);
147                }
148
149                $s = array();
150                foreach($tab as $ext){
151                        $s[] = "\\." . $ext;
152                }
153                $s = implode('|', $s);
154
155                return "/(".$s.")$/i";
156        }
157
158
159
160        /**
161         * Retourne la liste des sous-dossiers et fichiers (racine comprise)
162         *
163         * Fonction recursive.
164         *
165         * @param array $dossier
166         *     La racine dans laquelle la recherche est lancee
167         * @return array
168         *     Des chemins disques (dossiers & fichiers)
169         *
170        **/
171        private function get_chemins_fichiers($dossier){
172                $chemins = array();
173                $ereg_filtre_extensions = $this->ereg_filtre_extensions($this->ignorer_extensions);
174                if ($handle = opendir($dossier)) {
175                        $chemins[] = $dossier;
176                        while (false !== ($file = readdir($handle))) {
177                                if (!in_array($file, $this->ignorer) && !preg_match($ereg_filtre_extensions, $file)) {
178                                        // securiser...
179                                        if (substr($dossier, -1, 1) == "/"){
180                                                $path = $dossier.$file;
181                                        } else {
182                                                $path = $dossier."/".$file;
183                                        }
184                                        // ---
185                                        if (is_dir($path)){
186                                                $chemins = array_merge($chemins, $this->get_chemins_fichiers($path));
187                                        } else {
188                                                $chemins[] = $path;
189                                        }
190                                }
191                        }
192                        closedir($handle);
193                }
194                return $chemins;
195        }
196
197
198
199        /**
200         * Retourne la liste des chemins disques
201         * pour lesquelles chemin_base a été retiré.
202         *
203         * @param string $chemin_base
204         *     Chemin de base sur lequel calculer la partie relative
205         * @param array $chemins
206         *     Liste de chemins disque
207         * @return array
208         *     Des chemins relatifs au chemin_base
209        **/
210        private function get_chemins_relatifs($chemin_base, $chemins){
211                $log = "";
212                $lg = strlen($chemin_base);
213
214                $files = array();
215                foreach($chemins as $path){
216                        $f = substr($path, $lg);
217                        if (!in_array($f, $this->ignorer_extensions)){
218                                $files[] = $f;
219                        }
220                }
221
222                return $files;
223        }
224
225
226
227        /**
228         * Retourne un tableau des differences entre dossier1 et dossier2
229         * base sur la commande "fc" de Windows
230         *
231         * @return array
232         *    Tableau de la forme :
233         *    `array("diff"=>Texte, "affiche"=>Texte, "suppressions"=>array(noms de fichier))`
234         *
235        **/
236        private function get_diff_windows(){
237                // Liste des chemins vers les fichiers
238                $ldossier1 = $this->get_chemins_fichiers($this->dossier1);
239                $ldossier2 = $this->get_chemins_fichiers($this->dossier2);
240
241                // Liste des chemins relatifs
242                $files_dossier1 = $this->get_chemins_relatifs($this->dossier1, $ldossier1);
243                $files_dossier2 = $this->get_chemins_relatifs($this->dossier2, $ldossier2);
244
245
246                // Les fichiers qui ont ete supprimes (que dans dossier1)
247                $que_dossier1 = array_diff($files_dossier1, $files_dossier2);
248                // Les nouveaux fichiers crees (que dans dossier2)
249                $que_dossier2 = array_diff($files_dossier2, $files_dossier1);
250                // Les fichiers present des 2 cotes, qu'il faudra comparer
251                $les_deux = array_intersect($files_dossier2, $files_dossier1);
252
253                $tab = array();
254
255                // Liste des fichiers supprimes
256                $suppressions = "";
257                if (count($que_dossier1)>0){
258                        $tmp = implode("\n- ", $que_dossier1);
259                        $suppressions .= "Fichiers supprimés : ";
260                        $suppressions .= "\n- ".$tmp; 
261                        $tab[] = $suppressions."\n";
262                }
263               
264                // Liste des fichiers crees
265                $ajouts = "";
266                if (count($que_dossier2)>0){
267                        $tmp = implode("\n- ", $que_dossier2);
268                        $ajouts .= "Fichiers créés : ";
269                        $ajouts .= "\n- ".$tmp; 
270                        $tab[] = $ajouts."\n";
271                }
272               
273                // Liste des fichiers modifies
274                $diffs = "";
275                if (count($les_deux)>0){
276                        $diffs .= "Fichiers modifiés : ";
277                        $cwd = getcwd() . "\\";
278                        $ereg_filtre_extensions = $this->ereg_filtre_extensions($this->ignorer_extensions_complementaires);
279                        foreach($les_deux as $f){
280                                $path_dossier1 = str_replace("/", "\\", $cwd.$this->dossier1.$f);
281                                $path_dossier2 = str_replace("/", "\\", $cwd.$this->dossier2.$f);
282
283                                if (is_file($path_dossier2) && !preg_match($ereg_filtre_extensions, $f)){
284                                        $commande_diff = "fc /L /N $path_dossier1 $path_dossier2";
285                                        $diff = "";
286                                        exec($commande_diff, $diff);
287                                        // Depend surement de la langue de l'OS ??
288                                        if (!preg_match("/aucune diff.rence trouv/i", $diff[1])){
289                                                $tmp = implode("\n", $diff);
290                                                // Supprimer la partie absolue des path (pour plus de legerete...)
291                                                $tmp = str_replace(strtoupper($cwd), "", $tmp);
292                                                $di = "";
293                                                $di .= "\n\n".$f. " :";
294                                                $di .= "\n--------------------------------------------------------------------";
295                                                $di .= "\n".$tmp;
296                                                $diffs .= "\n".$di;
297                                        }
298                                }
299                        }
300                        $tab[] = $diffs."\n";
301                }
302
303                $diff = implode("\n", $tab);
304
305                $tab = array(
306                        "diff" => $diff,
307                        "affiche" => $diff, // diff plus humainement lisible
308                        "suppressions" => $que_dossier1
309                );
310               
311                return $tab;
312        }
313
314
315        /**
316         * Retourne un tableau des différences entre dossier1 et dossier2
317         * base sur la commande "diff" des systemes Unix
318         *
319         * @return array
320         *     Tableau de la forme :
321         *     `array("diff"=>Texte, "affiche"=>Texte, "suppressions"=>array(noms de fichier))`
322         *
323        **/
324        private function get_diff_unix(){
325                $diff = "";
326               
327                $options_ignorer = "";
328                foreach($this->ignorer as $ignore){
329                        $options_ignorer .= " -x ".$ignore;
330                }
331                $commande_diff = "diff -r".$options_ignorer." ".$this->dossier1." ".$this->dossier2;
332                exec($commande_diff, $diff);
333
334                // chaque ligne contient une info
335                // on cherche les fichiers presents dans l'ancienne version
336                // supprimes de la nouvelle pour avertir
337                $suppressions = array();
338                // on en profite pour raccourcir la ligne diff
339                // pour un retour plus humainement lisible
340                $affiche = $diff;
341                foreach($diff as $k => $l) {
342                        // trouver les suppressions
343                        // Only in ../plugins/fabrique_auto/.backup/prefixe/dir: fichier.php
344                        if ($l[0] == 'O' AND substr($l, 0, 7) == 'Only in') {
345                                if (strpos($l, $this->dossier1)) {
346                                        $suppressions[] = str_replace(': ', '/', trim(substr($l, 8 + strlen($this->dossier1))));
347                                }
348                                $affiche[$k] = "\n\n$l";
349                        }
350                        // rendre le diff plus lisible
351                        if ($l[0] == 'd' AND substr($l, 0, 4) == 'diff') {
352                                // ne garder que le chemin relatif du fichier
353                                $fichier = explode(' ', $l);
354                                $fichier = array_pop($fichier);
355                                $fichier = substr($fichier, strlen($this->dossier2));
356                                $affiche[$k] = "\n\n$fichier";
357                        }
358                }
359                $diff = implode("\n", $diff);
360                $affiche = implode("\n", $affiche);
361
362                $tab = array(
363                        "diff" => $diff,
364                        "affiche" => $affiche, // diff plus humainement lisible
365                        "suppressions" => $suppressions
366                );
367
368                return $tab;
369        }
370
371
372        /**
373         * Retourne un tableau des différences entre dossier1 et dossier2
374         *
375         * @exemple
376         *     ```
377         *     $fdiff->get_diff();
378         *     ```
379         *
380         * @return array
381         *     Tableau de la forme :
382         *     ```
383         *     array(
384         *       "diff"=>Texte,
385         *       "affiche"=>Texte, // diff plus lisible pour affichage
386         *       "suppressions"=>array(noms de fichier)
387         *     )
388         *     ```
389         *
390        **/
391        public function get_diff() {
392                if (_OS_SERVEUR == 'windows') {
393                        $tab = $this->get_diff_windows();
394                } else {
395                        $tab = $this->get_diff_unix();
396                }
397
398                return $tab;
399        }
400}
401
402?>
Note: See TracBrowser for help on using the repository browser.