fichier * - string $key : html d'insertion du fichier dans la page * - string|array $fichier : chemin du fichier, ou tableau (page,argument) si c'est un squelette * @param string $format * js ou css utilisé pour l'extension du fichier de sortie * @param array $callbacks * Tableau de fonctions à appeler : * - each_pre : fonction de préparation à appeler sur le contenu de chaque fichier * - each_min : fonction de minification à appeler sur le contenu de chaque fichier * - all_min : fonction de minification à appeler sur le contenu concatene complet, en fin de traitement * @return array * Tableau a 2 entrées retournant le nom du fichier et des commentaires HTML à insérer dans la page initiale */ function concatener_fichiers($files, $format = 'js', $callbacks = array()) { $nom = ""; if (!is_array($files) && $files) { $files = array($files); } if (count($files)) { $callback_min = isset($callbacks['each_min']) ? $callbacks['each_min'] : 'concatener_callback_identite'; $callback_pre = isset($callbacks['each_pre']) ? $callbacks['each_pre'] : ''; $url_base = self('&'); // on trie la liste de files pour calculer le nom // necessaire pour retomber sur le meme fichier // si on renome une url a la volee pour enlever le var_mode=recalcul // mais attention, il faut garder l'ordre initial pour la minification elle meme ! $dir = sous_repertoire(_DIR_VAR, 'cache-' . $format); $nom = $dir . md5(serialize($files) . serialize($callbacks)) . ".$format"; if ( (defined('_VAR_MODE') and _VAR_MODE == 'recalcul') or !file_exists($nom) ) { $fichier = ""; $comms = array(); $total = 0; $files2 = false; foreach ($files as $key => $file) { if (!is_array($file)) { // c'est un fichier $comm = $file; // enlever le timestamp si besoin $file = preg_replace(",[?].+$,", '', $file); // preparer le fichier si necessaire if ($callback_pre) { $file = $callback_pre($file); } lire_fichier($file, $contenu); } else { // c'est un squelette if (!isset($file[1])) { $file[1] = ''; } $comm = _SPIP_PAGE . "=$file[0]" . (strlen($file[1]) ? "($file[1])" : ''); parse_str($file[1], $contexte); $contenu = recuperer_fond($file[0], $contexte); // preparer le contenu si necessaire if ($callback_pre) { $contenu = $callback_pre($contenu, url_absolue(_DIR_RESTREINT ? generer_url_public($file[0], $file[1]) : $url_base)); } // enlever le var_mode si present pour retrouver la css minifiee standard if (strpos($file[1], 'var_mode') !== false) { if (!$files2) { $files2 = $files; } $old_key = $key; $key = preg_replace(',(&(amp;)?)?var_mode=[^&\'"]*,', '', $key); $file[1] = preg_replace(',&?var_mode=[^&\'"]*,', '', $file[1]); if (!strlen($file[1])) { unset($file[1]); } $files2 = array_replace_key($files2, $old_key, $key, $file); } } // passer la balise html initiale en second argument $fichier .= "/* $comm */\n" . $callback_min($contenu, $key) . "\n\n"; $comms[] = $comm; $total += strlen($contenu); } // calcul du % de compactage $pc = intval(1000 * strlen($fichier) / $total) / 10; $comms = "compact [\n\t" . join("\n\t", $comms) . "\n] $pc%"; $fichier = "/* $comms */\n\n" . $fichier; // si on a nettoye des &var_mode=recalcul : mettre a jour le nom // on ecrit pas dans le nom initial, qui est de toute facon recherche qu'en cas de recalcul // donc jamais utile if ($files2) { $files = $files2; $nom = $dir . md5(serialize($files) . serialize($callbacks)) . ".$format"; } $nom_tmp = $nom; $final_callback = (isset($callbacks['all_min']) ? $callbacks['all_min'] : false); if ($final_callback) { unset($callbacks['all_min']); $nom_tmp = $dir . md5(serialize($files) . serialize($callbacks)) . ".$format"; } // ecrire ecrire_fichier($nom_tmp, $fichier, true); clearstatcache(true, $nom_tmp); // ecrire une version .gz pour content-negociation par apache, cf. [11539] ecrire_fichier("$nom_tmp.gz", $fichier, true); if ($final_callback) { // closure compiler ou autre super-compresseurs // a appliquer sur le fichier final $encore = $final_callback($nom_tmp, $nom); // si echec, on se contente de la compression sans cette callback if ($encore !== $nom) { // ecrire ecrire_fichier($nom, $fichier, true); clearstatcache(true, $nom); // ecrire une version .gz pour content-negociation par apache, cf. [11539] ecrire_fichier("$nom.gz", $fichier, true); } } } } // Le commentaire detaille n'apparait qu'au recalcul, pour debug return array($nom, (isset($comms) and $comms) ? "\n" : ''); } /** * Une callback pour la minification par défaut * * Mais justement, par défaut on ne minifie rien ! * * @param string $contenu Contenu à minifier * @return string Contenu à minifier */ function &concatener_callback_identite(&$contenu) { return $contenu; } /** * Une callback pour ? * * @param array $tableau * * @param string $orig_key * Index dont on cherche la valeur actuelle * @param string $new_key * Nouvel index que l'on veut voir affecter de la valeur de la clé d'origine * @param mixed $new_value * Si rempli, la nouvelle clé prend cette valeur à la place * de la valeur de la clé d'origine * @return array * */ function &array_replace_key($tableau, $orig_key, $new_key, $new_value = null) { $t = array(); foreach ($tableau as $k => $v) { if ($k == $orig_key) { $k = $new_key; if (!is_null($new_value)) { $v = $new_value; } } $t[$k] = $v; } return $t; }