c29d558a85d3234db497b4b2df8dfa0ffa5b12e0
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2020 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Fonctions pour concaténer plusieurs fichiers en un
16 * @package SPIP\Compresseur\Concatener
18 if (!defined("_ECRIRE_INC_VERSION")) {
24 * Concaténer en un seul une liste de fichier,
25 * avec appels de callback sur chaque fichier,
26 * puis sur le fichier final
28 * Gestion d'un cache : le fichier concaténé n'est produit que si il n'existe pas
29 * pour la liste de fichiers fournis en entrée
33 * Liste des fichiers à concatener, chaque entrée sour la forme html=>fichier
34 * - string $key : html d'insertion du fichier dans la page
35 * - string|array $fichier : chemin du fichier, ou tableau (page,argument) si c'est un squelette
36 * @param string $format
37 * js ou css utilisé pour l'extension du fichier de sortie
38 * @param array $callbacks
39 * Tableau de fonctions à appeler :
40 * - each_pre : fonction de préparation à appeler sur le contenu de chaque fichier
41 * - each_min : fonction de minification à appeler sur le contenu de chaque fichier
42 * - all_min : fonction de minification à appeler sur le contenu concatene complet, en fin de traitement
44 * Tableau a 2 entrées retournant le nom du fichier et des commentaires HTML à insérer dans la page initiale
46 function concatener_fichiers($files, $format = 'js', $callbacks = array()) {
48 if (!is_array($files) && $files) {
49 $files = array($files);
52 $callback_min = isset($callbacks['each_min']) ?
$callbacks['each_min'] : 'concatener_callback_identite';
53 $callback_pre = isset($callbacks['each_pre']) ?
$callbacks['each_pre'] : '';
54 $url_base = self('&');
56 // on trie la liste de files pour calculer le nom
57 // necessaire pour retomber sur le meme fichier
58 // si on renome une url a la volee pour enlever le var_mode=recalcul
59 // mais attention, il faut garder l'ordre initial pour la minification elle meme !
60 $dir = sous_repertoire(_DIR_VAR
, 'cache-' . $format);
61 list($nom, $lastmodified) = concatener_nom_fichier_concat($dir, $files, $callbacks, $format);
63 (defined('_VAR_MODE') and _VAR_MODE
== 'recalcul')
65 or filemtime($nom) < $lastmodified
67 spip_log("concatener_fichiers: Recalculer $nom plus a jour", "compresseur" . _LOG_DEBUG
);
72 foreach ($files as $key => $file) {
73 if (!is_array($file)) {
76 // enlever le timestamp si besoin
77 $file = preg_replace(",[?].+$,", '', $file);
79 // preparer le fichier si necessaire
81 $file = $callback_pre($file);
84 lire_fichier($file, $contenu);
87 if (!isset($file[1])) {
90 $comm = _SPIP_PAGE
. "=$file[0]"
91 . (strlen($file[1]) ?
"($file[1])" : '');
92 parse_str($file[1], $contexte);
93 $contenu = recuperer_fond($file[0], $contexte);
95 // preparer le contenu si necessaire
97 $contenu = $callback_pre($contenu,
98 url_absolue(_DIR_RESTREINT ?
generer_url_public($file[0], $file[1]) : $url_base));
100 // enlever le var_mode si present pour retrouver la css minifiee standard
101 if (strpos($file[1], 'var_mode') !== false) {
106 $key = preg_replace(',(&(amp;)?)?var_mode=[^&\'"]*,', '', $key);
107 $file[1] = preg_replace(',&?var_mode=[^&\'"]*,', '', $file[1]);
108 if (!strlen($file[1])) {
111 $files2 = array_replace_key($files2, $old_key, $key, $file);
114 // passer la balise html initiale en second argument
115 $fichier .= "/* $comm */\n" . $callback_min($contenu, $key) . "\n\n";
117 $total +
= strlen($contenu);
120 // calcul du % de compactage
121 $pc = intval(1000 * strlen($fichier) / $total) / 10;
122 $comms = "compact [\n\t" . join("\n\t", $comms) . "\n] $pc%";
123 $fichier = "/* $comms */\n\n" . $fichier;
125 // si on a nettoye des &var_mode=recalcul : mettre a jour le nom
126 // on ecrit pas dans le nom initial, qui est de toute facon recherche qu'en cas de recalcul
130 list($nom, $lastmodified) = concatener_nom_fichier_concat($dir, $files, $callbacks, $format);
134 $final_callback = (isset($callbacks['all_min']) ?
$callbacks['all_min'] : false);
135 if ($final_callback) {
136 unset($callbacks['all_min']);
137 list($nom_tmp, $lastmodified) = concatener_nom_fichier_concat($dir, $files, $callbacks, $format);
140 ecrire_fichier($nom_tmp, $fichier, true);
141 clearstatcache(true, $nom_tmp);
142 // ecrire une version .gz pour content-negociation par apache, cf. [11539]
143 ecrire_fichier("$nom_tmp.gz", $fichier, true);
145 if ($final_callback) {
146 // closure compiler ou autre super-compresseurs
147 // a appliquer sur le fichier final
148 $encore = $final_callback($nom_tmp, $nom);
149 // si echec, on se contente de la compression sans cette callback
150 if ($encore !== $nom) {
152 ecrire_fichier($nom, $fichier, true);
153 clearstatcache(true, $nom);
154 // ecrire une version .gz pour content-negociation par apache, cf. [11539]
155 ecrire_fichier("$nom.gz", $fichier, true);
163 // Le commentaire detaille n'apparait qu'au recalcul, pour debug
164 return array($nom, (isset($comms) and $comms) ?
"<!-- $comms -->\n" : '');
168 * Calculer le nom de fichier concatene
169 * en tenant compte des timestamps :
170 * un changement de timestamp ne doit pas modifier le nom mais bien forcer une mise a jour du fichier concat si besoin
172 * @param array $files
173 * @param array $callbacks
174 * @param string $format
177 function concatener_nom_fichier_concat($dir, $files, $callbacks, $format) {
179 $file_wo_timestamp = [];
180 // on ignore les cles : seul le fichier inclu compte, pas la forme exacte de la balise html dans laquelle il est insere
181 foreach ($files as $k => $file) {
182 if (!is_array($file)){
183 if (strpos($file, "?")!==false){
184 $file = explode('?', $file, 2);
185 if (is_numeric(end($file))){
186 $lastmodified = max($lastmodified, end($file));
188 $file = reset($file);
191 $file_wo_timestamp[] = $file;
193 $nom_fichier_concat = $dir . md5(json_encode($file_wo_timestamp) . json_encode($callbacks)) . ".$format";
194 return array($nom_fichier_concat, $lastmodified);
198 * Une callback pour la minification par défaut
200 * Mais justement, par défaut on ne minifie rien !
202 * @param string $contenu Contenu à minifier
203 * @return string Contenu à minifier
205 function &concatener_callback_identite(&$contenu) {
210 * Une callback pour ?
212 * @param array $tableau
214 * @param string $orig_key
215 * Index dont on cherche la valeur actuelle
216 * @param string $new_key
217 * Nouvel index que l'on veut voir affecter de la valeur de la clé d'origine
218 * @param mixed $new_value
219 * Si rempli, la nouvelle clé prend cette valeur à la place
220 * de la valeur de la clé d'origine
224 function &array_replace_key($tableau, $orig_key, $new_key, $new_value = null) {
226 foreach ($tableau as $k => $v) {
227 if ($k == $orig_key) {
229 if (!is_null($new_value)) {