[SPIP] ~maj SPIP v3.0.17 --> v3.0.19
[lhc/web/clavette_www.git] / www / plugins-dist / compresseur / inc / compresseur_concatener.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Fonctions pour concaténer plusieurs fichiers en un
15 *
16 * @package SPIP\Compresseur\Concatener
17 */
18 if (!defined("_ECRIRE_INC_VERSION")) return;
19
20
21 /**
22 * Concaténer en un seul une liste de fichier,
23 * avec appels de callback sur chaque fichier,
24 * puis sur le fichier final
25 *
26 * Gestion d'un cache : le fichier concaténé n'est produit que si il n'existe pas
27 * pour la liste de fichiers fournis en entrée
28 *
29 *
30 * @param array $files
31 * Liste des fichiers à concatener, chaque entrée sour la forme html=>fichier
32 * - string $key : html d'insertion du fichier dans la page
33 * - string|array $fichier : chemin du fichier, ou tableau (page,argument) si c'est un squelette
34 * @param string $format
35 * js ou css utilisé pour l'extension du fichier de sortie
36 * @param array $callbacks
37 * Tableau de fonctions à appeler :
38 * - each_pre : fonction de préparation à appeler sur le contenu de chaque fichier
39 * - each_min : fonction de minification à appeler sur le contenu de chaque fichier
40 * - all_min : fonction de minification à appeler sur le contenu concatene complet, en fin de traitement
41 * @return array
42 * Tableau a 2 entrées retournant le nom du fichier et des commentaires HTML à insérer dans la page initiale
43 */
44 function concatener_fichiers($files,$format='js', $callbacks = array()){
45 $nom = "";
46 if (!is_array($files) && $files) $files = array($files);
47 if (count($files)){
48 $callback_min = isset($callbacks['each_min'])?$callbacks['each_min']:'concatener_callback_identite';
49 $callback_pre = isset($callbacks['each_pre'])?$callbacks['each_pre']:'';
50 $url_base = self('&');
51
52 // on trie la liste de files pour calculer le nom
53 // necessaire pour retomber sur le meme fichier
54 // si on renome une url a la volee pour enlever le var_mode=recalcul
55 // mais attention, il faut garder l'ordre initial pour la minification elle meme !
56 $dir = sous_repertoire(_DIR_VAR,'cache-'.$format);
57 $nom = $dir . md5(serialize($files).serialize($callbacks)) . ".$format";
58 if (
59 (defined('_VAR_MODE') AND _VAR_MODE=='recalcul')
60 OR !file_exists($nom)
61 ) {
62 $fichier = "";
63 $comms = array();
64 $total = 0;
65 $files2 = false;
66 foreach($files as $key=>$file){
67 if (!is_array($file)) {
68 // c'est un fichier
69 $comm = $file;
70 // enlever le timestamp si besoin
71 $file = preg_replace(",[?].+$,",'',$file);
72
73 // preparer le fichier si necessaire
74 if ($callback_pre)
75 $file = $callback_pre($file);
76
77 lire_fichier($file, $contenu);
78 }
79 else {
80 // c'est un squelette
81 if (!isset($file[1])) $file[1] = '';
82 $comm = _SPIP_PAGE . "=$file[0]"
83 . (strlen($file[1])?"($file[1])":'');
84 parse_str($file[1],$contexte);
85 $contenu = recuperer_fond($file[0],$contexte);
86
87 // preparer le contenu si necessaire
88 if ($callback_pre)
89 $contenu = $callback_pre($contenu, url_absolue(_DIR_RESTREINT?generer_url_public($file[0],$file[1]):$url_base));
90 // enlever le var_mode si present pour retrouver la css minifiee standard
91 if (strpos($file[1],'var_mode')!==false) {
92 if (!$files2) $files2 = $files;
93 $old_key = $key;
94 $key = preg_replace(',(&(amp;)?)?var_mode=[^&\'"]*,','',$key);
95 $file[1] = preg_replace(',&?var_mode=[^&\'"]*,','',$file[1]);
96 if (!strlen($file[1]))
97 unset($file[1]);
98 $files2 = array_replace_key($files2,$old_key,$key,$file);
99 }
100 }
101 // passer la balise html initiale en second argument
102 $fichier .= "/* $comm */\n". $callback_min($contenu, $key) . "\n\n";
103 $comms[] = $comm;
104 $total += strlen($contenu);
105 }
106
107 // calcul du % de compactage
108 $pc = intval(1000*strlen($fichier)/$total)/10;
109 $comms = "compact [\n\t".join("\n\t", $comms)."\n] $pc%";
110 $fichier = "/* $comms */\n\n".$fichier;
111
112 // si on a nettoye des &var_mode=recalcul : mettre a jour le nom
113 // on ecrit pas dans le nom initial, qui est de toute facon recherche qu'en cas de recalcul
114 // donc jamais utile
115 if ($files2) {
116 $files=$files2;
117 $nom = $dir . md5(serialize($files).serialize($callbacks)) . ".$format";
118 }
119
120 $nom_tmp = $nom;
121 $final_callback = (isset($callbacks['all_min'])?$callbacks['all_min']:false);
122 if ($final_callback){
123 unset($callbacks['all_min']);
124 $nom_tmp = $dir . md5(serialize($files).serialize($callbacks)) . ".$format";
125 }
126 // ecrire
127 ecrire_fichier($nom_tmp,$fichier,true);
128 spip_clearstatcache(true,$nom_tmp);
129 // ecrire une version .gz pour content-negociation par apache, cf. [11539]
130 ecrire_fichier("$nom_tmp.gz",$fichier,true);
131
132 if ($final_callback){
133 // closure compiler ou autre super-compresseurs
134 // a appliquer sur le fichier final
135 $encore = $final_callback($nom_tmp, $nom);
136 // si echec, on se contente de la compression sans cette callback
137 if ($encore!==$nom){
138 // ecrire
139 ecrire_fichier($nom,$fichier,true);
140 spip_clearstatcache(true,$nom);
141 // ecrire une version .gz pour content-negociation par apache, cf. [11539]
142 ecrire_fichier("$nom.gz",$fichier,true);
143 }
144 }
145 }
146
147
148 }
149
150 // Le commentaire detaille n'apparait qu'au recalcul, pour debug
151 return array($nom, (isset($comms) AND $comms) ? "<!-- $comms -->\n" : '');
152 }
153
154 /**
155 * Une callback pour la minification par défaut
156 *
157 * Mais justement, par défaut on ne minifie rien !
158 *
159 * @param string $contenu Contenu à minifier
160 * @return string Contenu à minifier
161 */
162 function &concatener_callback_identite(&$contenu){
163 return $contenu;
164 }
165
166 /**
167 * Une callback pour ?
168 *
169 * @param array $tableau
170 *
171 * @param string $orig_key
172 * Index dont on cherche la valeur actuelle
173 * @param string $new_key
174 * Nouvel index que l'on veut voir affecter de la valeur de la clé d'origine
175 * @param mixed $new_value
176 * Si rempli, la nouvelle clé prend cette valeur à la place
177 * de la valeur de la clé d'origine
178 * @return array
179 *
180 */
181 function &array_replace_key($tableau,$orig_key,$new_key,$new_value=null){
182 $t = array();
183 foreach($tableau as $k=>$v) {
184 if ($k==$orig_key) {
185 $k=$new_key;
186 if (!is_null($new_value)) {
187 $v = $new_value;
188 }
189 }
190 $t[$k] = $v;
191 }
192 return $t;
193 }