Ejemplo n.º 1
0
/**
 * Produire un fichier statique a partir d'un squelette dynamique
 * Permet ensuite a apache de le servir en statique sans repasser
 * par spip.php a chaque hit sur le fichier
 * si le format (css ou js) est passe dans contexte['format'], on l'utilise
 * sinon on regarde si le fond finit par .css ou .js
 * sinon on utilie "html"
 *
 * @param string $fond
 * @param array $contexte
 * @param array $options
 * @param string $connect
 * @return string
 */
function produire_fond_statique($fond, $contexte = array(), $options = array(), $connect = '')
{
    if (isset($contexte['format'])) {
        $extension = $contexte['format'];
        unset($contexte['format']);
    } else {
        $extension = "html";
        if (preg_match(',[.](css|js|json)$,', $fond, $m)) {
            $extension = $m[1];
        }
    }
    // recuperer le contenu produit par le squelette
    $options['raw'] = true;
    $cache = recuperer_fond($fond, $contexte, $options, $connect);
    // calculer le nom de la css
    $dir_var = sous_repertoire(_DIR_VAR, 'cache-' . $extension);
    $nom_safe = preg_replace(",\\W,", '_', str_replace('.', '_', $fond));
    $filename = $dir_var . $extension . "dyn-{$nom_safe}-" . substr(md5($fond . serialize($contexte) . $connect), 0, 8) . ".{$extension}";
    // mettre a jour le fichier si il n'existe pas
    // ou trop ancien
    // le dernier fichier produit est toujours suffixe par .last
    // et recopie sur le fichier cible uniquement si il change
    if (!file_exists($filename) or !file_exists($filename . ".last") or isset($cache['lastmodified']) and $cache['lastmodified'] and filemtime($filename . ".last") < $cache['lastmodified'] or defined('_VAR_MODE') and _VAR_MODE == 'recalcul') {
        $contenu = $cache['texte'];
        // passer les urls en absolu si c'est une css
        if ($extension == "css") {
            $contenu = urls_absolues_css($contenu, test_espace_prive() ? generer_url_ecrire('accueil') : generer_url_public($fond));
        }
        // ne pas insérer de commentaire si c'est du json
        if ($extension != "json") {
            $comment = "/* #PRODUIRE{fond={$fond}";
            foreach ($contexte as $k => $v) {
                $comment .= ",{$k}={$v}";
            }
            // pas de date dans le commentaire car sinon ca invalide le md5 et force la maj
            // mais on peut mettre un md5 du contenu, ce qui donne un aperu rapide si la feuille a change ou non
            $comment .= "}\n   md5:" . md5($contenu) . " */\n";
        }
        // et ecrire le fichier
        ecrire_fichier($filename . ".last", $comment . $contenu);
        // regarder si on recopie
        if (!file_exists($filename) or md5_file($filename) !== md5_file($filename . ".last")) {
            @copy($filename . ".last", $filename);
            spip_clearstatcache(true, $filename);
            // eviter que PHP ne reserve le vieux timestamp
        }
    }
    return $filename;
}
Ejemplo n.º 2
0
/**
 * Invalidates a PHP file from any active opcode caches.
 *
 * If the opcode cache does not support the invalidation of individual files,
 * the entire cache will be flushed.
 * kudo : http://cgit.drupalcode.org/drupal/commit/?id=be97f50
 *
 * @param string $filepath
 *   The absolute path of the PHP file to invalidate.
 */
function spip_clear_opcode_cache($filepath)
{
    spip_clearstatcache(true, $filepath);
    // Zend OPcache
    if (function_exists('opcache_invalidate')) {
        opcache_invalidate($filepath, true);
    }
    // APC.
    if (function_exists('apc_delete_file')) {
        // apc_delete_file() throws a PHP warning in case the specified file was
        // not compiled yet.
        // @see http://php.net/apc-delete-file
        @apc_delete_file($filepath);
    }
}
/**
 * Concaténer en un seul une liste de fichier,
 * avec appels de callback sur chaque fichier,
 * puis sur le fichier final
 *
 * Gestion d'un cache : le fichier concaténé n'est produit que si il n'existe pas
 * pour la liste de fichiers fournis en entrée
 *
 *
 * @param array $files
 *     Liste des fichiers à concatener, chaque entrée sour la forme html=>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);
            spip_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);
                    spip_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) ? "<!-- {$comms} -->\n" : '');
}
Ejemplo n.º 4
0
/**
 * Minification additionnelle de JS
 * 
 * Compacter du javascript plus intensivement
 * grâce au google closure compiler
 *
 * @param string $content
 *     Contenu JS à compresser
 * @param bool $file
 *     Indique si $content est ou non un fichier, et retourne un fichier dans ce dernier cas
 *     Si $file est une chaîne, c'est un nom de ficher sous lequel on écrit aussi le fichier destination
 * @return string
 *     Contenu JS compressé
 */
function minifier_encore_js($content, $file = false)
{
    # Closure Compiler n'accepte pas des POST plus gros que 200 000 octets
    # au-dela il faut stocker dans un fichier, et envoyer l'url du fichier
    # dans code_url ; en localhost ca ne marche evidemment pas
    if ($file) {
        $nom = $content;
        lire_fichier($nom, $content);
        $dest = dirname($nom) . '/' . md5($content . $file) . '.js';
        if (file_exists($dest) and (!is_string($file) or file_exists($file))) {
            if (filesize($dest)) {
                return is_string($file) ? $file : $dest;
            } else {
                spip_log("minifier_encore_js: Fichier {$dest} vide", _LOG_INFO);
                return $nom;
            }
        }
    }
    if (!$file and strlen($content) > 200000) {
        return $content;
    }
    include_spip('inc/distant');
    $datas = array('output_format' => 'text', 'output_info' => 'compiled_code', 'compilation_level' => 'SIMPLE_OPTIMIZATIONS');
    if (!$file or strlen($content) < 200000) {
        $datas['js_code'] = $content;
    } else {
        $datas['url_code'] = url_absolue($nom);
    }
    $cc = recuperer_page('http://closure-compiler.appspot.com/compile', $trans = false, $get_headers = false, $taille_max = null, $datas, $boundary = -1);
    if ($cc and !preg_match(',^\\s*Error,', $cc)) {
        spip_log('Closure Compiler: success');
        $cc = "/* {$nom} + Closure Compiler */\n" . $cc;
        if ($file) {
            ecrire_fichier($dest, $cc, true);
            ecrire_fichier("{$dest}.gz", $cc, true);
            $content = $dest;
            if (is_string($file)) {
                ecrire_fichier($file, $cc, true);
                spip_clearstatcache(true, $file);
                ecrire_fichier("{$file}.gz", $cc, true);
                $content = $file;
            }
        } else {
            $content =& $cc;
        }
    } else {
        if ($file) {
            spip_log("minifier_encore_js:Echec appel Closure Compiler. Ecriture fichier {$dest} vide", _LOG_INFO_IMPORTANTE);
            ecrire_fichier($dest, '', true);
        }
    }
    return $content;
}