Stocker et manipuler les ressources distantes avec système de cache

  • De le 17 janvier 2010
  • Difficulté : 3/4

Stocker et manipuler les ressources distantes avec système de cache Stocker l'intégralité des ressources externes (images, flux, scripts...) sur son serveur lorsque cela est possible est une bonne habitude à prendre, facile à mettre en place. A titre d'exemple nous allons voir comment mettre en cache le script Google Analytics sur son propre serveur avec Magento.

Stocker sur son serveur les ressources distantes permet de gérer à sa convenance les en-têtes des documents, de réduire les DNS lookup et de ne pas dépendre de la charge du serveur qui héberge les fichiers dont nous avons besoin. Cette technique est d'ailleurs souvent préconisée par les outils d'analyse de performance de site.

Ces ressources externes sont bien entendus amenées à évoluer, parfois rapidement, notamment pour les flux d'actualités. L'objectif est donc de les stocker à intervalles réguliers sur le serveur avec un système de cache.

La fonction suivante va conserver dans un répertoire donné un fichier accessible depuis une URL spécifique :

Fonction cacheFile

function cacheFile($url,$age,$cacheDir,$name='') {
        $filename = strlen($name) ? $cacheDir.'/'.$name : $cacheDir.'/'.md5($url);
        $fetch = true;

        if(file_exists($filename)) $fetch = (filemtime($filename) < (time()-$age));

        if($fetch) {
                exec('wget -N -O '.$filename." \"".$url."\"");
                exec('touch '.$filename);
        }
        return $filename;
}

Par exemple, pour manipuler après mise en cache les données contenues dans le fichier flux.xml accessible à l'adresse http://www.site.com/flux.xml :

Manipuler un flux en cache

$file = cacheFile('http://www.site.com/flux.xml',86400,'/cache','flux.xml');
$_xml = simplexml_load_file($file);

Dans cet exemple le fichier flux.xml est stocké dans le dossier cache à la racine puis mis à jour sur le serveur toutes les 24 heures (86400 secondes).

NB : l'option allow_url_fopen doit être activée depuis le php.ini (Plus d'informations) :

php.ini

; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
allow_url_fopen = On

Mettre en cache le script Google Analytics sur Magento

Pour un cas plus concret et avec Magento, nous allons appliquer l'astuce n°1 de l'article Top 3 Speed Tips for Sites using Google Analytics du site AskApache, c'est à dire stocker le script ga.js de Google Analytics sur le serveur (et éviter le très courant "En attente de google-analytics.com").

Pour cela il va falloir effectuer une petite surcharge du module GoogleAnalytics de Magento. Google Analytics s'active depuis le menu Système > Configuration > Ventes > API Google > Google Analytics.

Google Analytics

Architecture du module

  • app/code/local/Magentix/CacheAnalytics/Block/
  • Ga.php
  • app/code/local/Magentix/CacheAnalytics/etc/
  • config.xml
  • app/etc/modules/
  • Magentix_CacheAnalytics.xml

Développement du module

Depuis Magento 1.4, la version asynchrone d'Analytics est implémenté. Le module se base sur la version 1.3. Il est nécessaire de l'adapater pour un magento supérieur à 1.4.

Nous allons adapter la fonction cacheFile spécifiquement pour la mise en cache du script ga.js d'Analytics, avec les méthodes offertes par l'API de Magento :

Fonction cacheAnalytics

private function cacheAnalytics() {
        $protocol = Mage::app()->getStore()->isCurrentlySecure();
        $dir = Mage::getBaseDir('media').DS.'analytics';
        
        $gaJsHost = $protocol == 'https' ? 'https://ssl.' : 'http://www.';
        $url = $gaJsHost.'google-analytics.com/ga.js';
                
        $filename = $protocol == 'https' ? 'ga-2.js' : 'ga-1.js';
        $file = $dir.DS.$filename;
                
        $fetch = true;
                
        if(realpath($file)) $fetch = (filemtime($file) < (time()-86400));

        if($fetch) {
                $ioAdapter = new Varien_Io_File();
                $ioAdapter->setAllowCreateFolders(true);
                $ioAdapter->checkAndCreateFolder($dir);
                $ioAdapter->cp($url,$file);
        }
        return $this->getUrl('media/analytics').$filename;
}

Le fichier ga-1.js (ou ga-2.js selon le protocole utilisé) sera enregistré dans le dossier media/analytics, et mis à jour toutes les 24 heures. On utilisera ce fichier dans le code d'Analytics au lieu du ga.js accessible sur le site de google-analytics.com.

Finallement, la classe Magentix_CacheAnalytics_Block_Ga contiendra le code suivant :

app/code/local/Magentix/CacheAnalytics/Block/Ga.php

<?php

class Magentix_CacheAnalytics_Block_Ga extends Mage_GoogleAnalytics_Block_Ga {

        protected function _toHtml() {
                if (!Mage::getStoreConfigFlag('google/analytics/active')) {
                        return '';
                }
                
                $this->addText('<-- BEGIN GOOGLE ANALYTICS CODE -->
<script type="text/javascript">
//<![CDATA[
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src=\''.$this->cacheAnalytics().'\' type=\'text/javascript\'%3E%3C/script%3E"));
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
var pageTracker = _gat._getTracker("' . $this->getAccount() . '");
pageTracker._trackPageview("'.$this->getPageName().'");
//]]>
</script>
<-- END GOOGLE ANALYTICS CODE -->
                ');

                $this->addText($this->getQuoteOrdersHtml());

                if ($this->getGoogleCheckout()) {
                        $protocol = Mage::app()->getStore()->isCurrentlySecure() ? 'https' : 'http';
                        $this->addText('<script src="'.$protocol.'://checkout.google.com/files/digital/ga_post.js" type="text/javascript"></script>');
                }

                return Mage_Core_Block_Text::_toHtml();
        }
        
        private function cacheAnalytics() {
                $protocol = Mage::app()->getStore()->isCurrentlySecure();
                $dir = Mage::getBaseDir('media').DS.'analytics';
        
                $gaJsHost = $protocol == 'https' ? 'https://ssl.' : 'http://www.';
                $url = $gaJsHost.'google-analytics.com/ga.js';
                
                $filename = $protocol == 'https' ? 'ga-2.js' : 'ga-1.js';
                $file = $dir.DS.$filename;
                
                $fetch = true;
                
                if(realpath($file)) $fetch = (filemtime($file) < (time()-86400));

                if($fetch) {
                        $ioAdapter = new Varien_Io_File();
                        $ioAdapter->setAllowCreateFolders(true);
                        $ioAdapter->checkAndCreateFolder($dir);
                        $ioAdapter->cp($url,$file);
                }
                return $this->getUrl('media/analytics').$filename;
        }
}

Nottez l'appel à la fonction _toHtml() de la classe Mage_Core_Block_Text et non de la classe parente Mage_GoogleAnalytics_Block_Ga pour éviter la duplication du code dans la page (et l'inutilité de la surcharge).

Il ne reste plus qu'à configurer le module et à le déclarer :

app/code/local/Magentix/CacheAnalytics/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_CacheAnalytics>
            <version>1.0</version>
        </Magentix_CacheAnalytics>
    </modules>
    <global>
        <blocks>
            <googleanalytics>
                <rewrite>
                    <ga>Magentix_CacheAnalytics_Block_Ga</ga>
                </rewrite>
            </googleanalytics>
        </blocks>
    </global>
</config>

app/etc/modules/Magentix_CacheAnalytics.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_CacheAnalytics>
            <active>true</active>
            <codePool>local</codePool>
        </Magentix_CacheAnalytics>
    </modules>
</config>

Reste à vérifier que la compression gzip est appliquée sur le fichier, et l'activer si ce n'est pas le cas.

commentaires

Commentez cet article : Stocker et manipuler les ressources distantes avec système de cache