Il existe différentes méthodes et outils permettant de backuper ses bases de données MySQL. Cela va d’une sauvegarde “offline” par copie des fichiers du dossier data de mysql à une sauvegarde “online” avec mysqlhotcopy ou mysqldump , en passant par l’utilisation d’un serveur esclave MySQL réplicant votre serveur maître.
Ne possédant qu’un seul serveur, il est difficile de faire de la réplication. C’est ainsi que j’utilise les outils mysqlhotcopy et mysqldump pour réaliser les sauvegardes de mon serveur SQL.
Pour une sauvegarde du jour J, j’utilise toujours deux backups :
mysqldump permet de sauvegarder des dumps SQL soit d’une base entière, soit de tables précises dans cette base, soit d’enregistrements précis (option –where), soit carrément sauvegarder toutes les bases (option –all-databases). C’est d’ailleurs cette dernière option que j’utilisais jusqu’à présent, avant d’être confronté au problème suivant :
Je dispose d’un fichier de dump complet de mes bases de données, or ce fichier fait plusieurs centaines de mégaoctets. Je peux aisément restaurer tout le serveur. Mais si j’ai besoin de restaurer une table particulière, comment procéder ?
Etant donné la taille du fichier, toute édition classique afin de copier coller la partie intéressante n’est pas possible. Peut-être que la solution se trouve dans une utilisation astucieuse de cat, grep, awk etc … mais je n’ai pas cherché de ce coté là. Je n’ai pas trouvé non plus du coté de la suite MySQL Workbench qui, bien qu’elle fournisse des outils très intéressants dans la modélisation SQL, celle-ci n’offre pas d’analyseur au niveaux des données.
Exemple : Il est possible d’importer un gros dump SQL dans MySQL Workbench qui permet de reconsituter par rétro-ingénierie la modélisation structurelle des bases de données et des tables contenues dans le script. On peut ensuite exporter les différents objets reconstitués (base ou table par exemple), mais l’export ne concerne que la structure de l’objet, et non ses données (on exporte ainsi le script permettant de créer la table ou la base, mais pas les enregistrements originaux de celles-ci)
Voici la solution que j’ai donc implémentée :
Cette solution a plusieurs avantages :
#!/bin/bash
#Dump table par table MySQL - phpnews.fr
#Déclaration de l'utilisateur MySQL aux droits suffisants pour parcourir vos bases de données
#Droit requis : SELECT global, LOCK TABLES
user='backuper'
pass='p@ssw0rd'
#On définit un nom temporaire utilisé par le script (ici la date jusqu'à la minute)
dirname="dump_`date +%d`.`date +%m`.`date +%y`@`date +%H`h`date +%M`"
#On crée sur le disque un répertoire temporaire (changer le chemin précédant /$dirname)
mkdir "/$dirname"
#On place dans un tableau le nom de toutes les bases de données du serveur
#On peut choisir ici d'exclure certaines bases de données de la sauvegarde grâce à la clause LIKE
#Ex : -e "show databases LIKE 'blog_%'"
databases=( $(mysql -u $user -p"$pass" -e "show databases" | grep -v Database) )
#Pour chacune des bases de données trouvées ...
for database in ${databases[@]}
do
#... on crée dans le dossier temporaire un dossier portant le nom de la base
mkdir "/${dirname}/${database}"
#... on récupère chacune des tables de cette base de données dans un tableau ...
tables=( $(mysql $database -u $user -p$pass -e 'show tables' | grep -v Tables_in) )
#... et on parcourt chacune de ces tables ...
for table in ${tables[@]}
do
#... que l'on dump avec mysqldump dans un fichier portant le nom de la table dans le dossier de la bdd parcourue
$(mysqldump -u $user -p$pass --quick --add-locks --lock-tables --extended-insert $database $table > /${dirname}/${database}/${table}.sql)
done
done
#On bzip le tout
tar -cjf /home/server/backup/sql/dump_tables/tables_${dirname}.tar.bz2 /$dirname/
#On supprime le répertoire temporaire
rm -rf /$dirname/
Et voilà le travail
Note : Ce script pose un problème de respect de la consistance de la base de donnée car les différentes tables ne sont pas sauvegardées au même moment. Je vous invite à lire les commentaires de ce billet et d’utiliser ce script avec discernement.
Sun microsystems vient d'annoncer la disponibilité de son pack AMP pour systèmes d'exploitation Solaris et Linux.
Ce pack est constitué du serveur HTTP Apache, du système de gestion de base de données MySQL et du langage PHP (et PERL). Le pack est disponible en téléchargement sur le site de Sun.
PHP et MySQL ne font l'objet d'aucune alerte de sécurité dans leurs versions courantes :
PHP 5.2.6 et 4.4.8; MySQL 5.0.51 (communauté) , 5.1.24-rc et 6.0.4.
Les mises à jour sont recommandées vers ces versions.
2 alertes de sécurité ont été émises cette semaine, concernant des applications suivantes :
Claroline et phpMyAdmin

Edit : il suffit que j'écrive un billet sur le sujet pour que la RC2 sorte avec enfin la correction des problèmes d'URL Alias. La version finale est aussi annoncée d'ici une à deux semaines sur la mailing liste si tout va bien.
eZ Publish 4.0 est sorti en décembre 2007 et depuis rien, aucune version stable. 8 mois c'est vraiment très très très long, il y a donc forcément des bugs gênants dans eZ Publish 4.0 d'autant plus que cette version est un portage vers PHP5 de la version 3.10 ce qui occasionne encore quelques bugs supplémentaires. La roadmap du bugtracker liste les problèmes résolus et non résolus mais il n'est pas toujours simple de faire le lien entre un comportement suspect et un bug dans cette liste.
Par exemple en développant la nouvelle version de ce site, je me suis trouvé face à plusieurs problèmes qui ont nécessité l'inclusion de patchs issus du SVN .
Il s'agit du bug #12175 qui empêche l'utilisation des cache-block expirant avec une sous-arborescence . Pour règler ce problème sans passer à la version 4.0.1rc1 il faut appliquer 3 patchs successifs sur l'arborescence d'eZ Publish 4.
$ cd /tmp $ wget http://pwet.fr/content/download/71716/214901/file/patch_cache_block_12175.tar.gz $ tar -zxvf patch_cache_block_12175.tar.gz $ cd /path/to/ez/publish/ $ patch -p0 < /tmp/01_cache-block.patch $ patch -p0 < /tmp/02_cache-block.patch $ patch -p0 < /tmp/03_cache-block.patch
Les erreurs sur l'application du patch sur le change log peuvent être tranquillement ignorées.
Celui la, c'est un bug vicieux , on s'en rend compte lors de la mise en production quand la machine est à plat par tous les convert (ou apache si on utilise GD) en train de générer les différentes variations encore et encore. 80 de load average sur ma pauvre Dedibox, elle a du avoir chaud ;-)
Là un seul patch est nécessaire et c'est immédiat et magique sur la charge de la machine
$ cd /tmp $ wget http://pwet.fr/content/download/71717/214904/file/image_variations.patch $ cd /path/to/ez/publish $ patch -p0 < /tmp/image_variations.patch
J'ai pas eu d'autres bugs bloquants (enfin je les ai pas encore remarqué :)), j'en ai d'ailleurs découvert un sur le SmartCacheClear avec les keywords , la correction est dans le rapport et tient sur une unique ligne.
Ces vidéos sont publiés sur les sites de partagent de vidéo. Ce sont des tutoriels enregistrés, des sessions de conférences, des screencast ou encore des slides de conférences.
N'hésitez pas à nous contacter pour signaler tout media qui mérite d'être ajouté à cette liste.
Ce texte est une des traductions d'une série d'articles de Lorenzo Alberton
(original)
La plupart des classes de pagination PHP peuvent fonctionner très bien avec des paramètres GET, correctement envoyés par les pages.
Cependant, rares sont celles qui vous laissent le contrôle sur les liens qu'elles créent.
Ceci peut être particulièrement ennuyant quand vous travaillez avec des cool URL (grâce à mod_rewrite ordonne ou fait à la main par votre contrôleur) et la classe de de pagination ne peut pas les respecter, en affichant les liens réels et laids.
Si le scénario ci-dessus n'est pas nouveau pour vous, alors vous devriez probablement tester PEAR::Pager.
C'est un paquet entièrement personnalisable qui devrait satisfaire tous vos besoins, y compris votre format préféré de lien.
Supposons-vous ont un site de commerce électronique, avec un catalogue de produit que l'utilisateur peut passer en revue par catégorie.
Par exemple, pour énumérer tous les produits de la catégorie AAA, vous passez ce paramètre à votre page : http://monserveur.com/produits.php?cat=AAA.
Si le catalogue est assez grand, la dispersion des produits dans plusieurs pages serait une décision intéressante,
mais maintenant vous devez également passer le numéro de page à l'URL : http://monserveur.com/produits.php?cat=AAA&pageID=3.
Naturellement votre application intelligente peut produire des URL plus propres, comme ceci : /produits/AAA/3.html qui sont facilement décodés par le mod_rewrite.
Voyons l'exemple de règle .htaccess pour cette transformation d'URL :
[apache] RewriteEngine on RewriteBase / RewriteRule ^produits/(\w+)/(\d+)\.html$ /produits.php?cat=$1&pageID=$2 [L]
Normalement, la classe de pagination les paramètres de cat et de pageID et établirait les liens comme d'habitude, c.-à-d.
/produits.php?cat=AAA&pageID=1 /produits.php?cat=AAA&pageID=2 ... /produits.php?cat=AAA&pageID=6
mais vous pouvez apprendre à PEAR::Pager à produire les liens qui respectent votre convention :
[php]
<?php
require_once 'Pager/Pager.php';
//toujours valider paramètres GET
if (!empty($_GET['cat']) && $myApp->is_valid_cat($_GET['cat'])) {
$cat = $_GET['cat'];
} else {
$cat = 'AAA'; //default category
}
// Récupération des produits.
// S'il y a beaucoup de produits,
// vous pouvez envisager d'employer les fonctions de Pager_Wrapper
$produitList = $myApp->getProductsByCat($cat);
$pager_params = array(
'mode' => 'Sliding',
'append' => false, //ne pas ajouter les paramètres GET à l'URL
'path' => 'http://monserveur.com/produits/' . $cat,
'fileName' => '%d.html', //Pager remplace "%d" par le numéro de la page
'perPage' => 10, //afficher 10 articles par page
'itemData' => $produitList,
);
$pager = & Pager::factory($pager_params);
$data = $pager->getPageData();
//Afficher les produits de la page courante
echo 'Données de la page courante: ';
print_r($data);
//afficher les liens pour la navigation dans la catégorie courante
echo $pager->links;
?>
Comme vous pouvez voir, vous pouvez dire au pager le chemin et le nom de fichier qu'il devrait employer.
N'oubliez pas de placer l'option de append à FALSE, sinon le pager essayera d'apposer les vars GET à l'URL comme d'habitude.
Et si le numéro de la page dans votre url se trouve dans le path et non dans nom fichier?
Ca pourrait ressembler à un problème, puisque Pager recherche la chaîne « %d » dans le paramètre nom de fichier, et se plaint s'il ne peut pas y trouver cette chaîne.
Non, vous ne pouvez pas le mettre dans le paramètre path, mais puisque le pager combinera simplement les paramètres path et nom de fichier pour former l'URL, nous pouvons le duper et mettre une partie du path dans le nom de fichier lui-même.
Pour le moment, si nous avons une url comme
http://monserveur.com/produits/AAA/3/index.html,
où "3" est le numéro de la page,
cette règle de mod_rewrite et ce script php le feront fonctionner:
[apache] RewriteEngine on RewriteBase / RewriteRule ^produits/(\w+)/(\d+)/index\.html$ /produits.php?cat=$1&pageID=$2 [L]
[php]
<?php
require_once 'Pager/Pager.php';
// ...
$pager_params = array(
'mode' => 'Sliding',
'append' => false, //ne pas ajouter les paramètres GET à l'URL
'path' => 'http://monserveur.com/produits/' . $cat,
'fileName' => '%d/index.html', //Pager remplaces "%d" par le numéro de la page
'perPage' => 10, //afficher 10 articles par page
'itemData' => $produitList,
);
$pager = & Pager::factory($pager_params);
$data = $pager->getPageData();
//afficher les produits de la page courante
echo 'Données de la page courante: ';
print_r($data);
//afficher les liens pour la navigation dans la catégorie courante
echo $pager->links;
?>
Voilà c'est fait. J'espère que ce tuto était utile.
PHP et MySQL ne font l'objet d'aucune alerte de sécurité dans leurs versions courantes :
PHP 5.2.6 et 4.4.9; MySQL 5.0.67 (communauté) , 5.1.26 et 6.0.5.
Les mises à jour sont recommandées vers ces versions.
7 alertes de sécurité ont été émises cette semaine, concernant des applications suivantes :
Gallery, Joomla, PHP Nuke, XAMPP, Xoops, e107 et phpMyAdmin
Ce texte est une des traductions d'une série d'articles de Lorenzo Alberton
Vous avez probablement vu beaucoup de sites Web comporter des articles longs et détaillés, qui sont coupés en paragraphes, chacun présenté dans une page séparée.
Les utilisateurs préfèrent souvent lire les morceaux courts du texte au lieu de faire défiler une très(trop) longue page (à moins qu'ils ne veulent l'imprimer).
Dans ce tuto, nous allons voir comment nous pouvons établir un système de paginations d'article, a l'aide de PEAR::Pager.
Nous aurons besoin de deux tables pour stocker nos articles :
Techniquement, nous pourrions employer juste une table, utilisant quelques délimiteurs spéciaux incorporés dans le texte (tel que le « ====FIN DE PAGE====") pour découper les paragraphes, mais croyez moi qu'à la longue cette une solution bien meilleure
[SQL] CREATE TABLE articles ( id INTEGER NOT NULL, title VARCHAR(250) NOT NULL, abstract TEXT, submission_date TIMESTAMP NOT NULL, author_id INTEGER NOT NULL, CONSTRAINT articles_pkey PRIMARY KEY(id) ); CREATE TABLE paragraphs ( article_id INTEGER NOT NULL, paragraph_id INTEGER NOT NULL, title VARCHAR(250), content TEXT, CONSTRAINT paragraphs_pkey PRIMARY KEY(article_id, paragraph_id), CONSTRAINT paragraphs_fk FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE );
Voici quelques données d'exemple si vous voulez tester tout en lisant ce tuto :
[SQL] -- Premier Article INSERT INTO articles (id, title, abstract, submission_date, author_id) VALUES ( 1, 'How to navigate through the paragraphs of an article with Pager', 'You\'ve probably seen a lot of websites featuring long, detailed articles, which are split into paragraphs, each of them in a separate page. Users often prefer reading short chunks of text instead of scrolling a very long page (unless they want to print the page, then the opposite applies). In this tutorial, we\'re going to see how we can build an article pagination system, with a little help from PEAR::Pager.', CURRENT_TIMESTAMP, 1 ); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 1, 'The database structure', 'First paragraph here'); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 2, 'Sample data', 'Second paragraph here'); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 3, 'Showtime', 'Third paragraph here'); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 4, 'Alternate navigation', 'Fourth paragraph here'); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 5, 'Article summary', 'Fifth paragraph here'); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (1, 6, 'Printer friendly version', 'Sixth paragraph here'); -- Second Article INSERT INTO articles (id, title, abstract, submission_date, author_id) VALUES ( 2, 'PEAR::Pager tutorials', 'New series of tutorials about PEAR::Pager', CURRENT_TIMESTAMP, 1 ); INSERT INTO paragraphs (article_id, paragraph_id, title, content) VALUES (2, 1, 'Articles index', '1. How to efficiently paginate database results. 2. Create pretty links with Pager and mod_rewrite. 3. Navigation with Pager and AJAX (or simple Javascript). 4. Article pagination.');
Maintenant que nous sommes ok avec la structure de base de données, nous pouvons afficher les articles sur notre site, un paragraphe par la page.
Pour cette tâche, nous allons employer PEAR::MDB2 DBAL et le bien pratique Pager_Wrapper que nous avons déjà vu dans un tuto précédent :
[php]
<?php
//Copier le fichier Pager_Wrapper file là où il peut-être inclu
require_once 'Pager_Wrapper.php';
require_once 'MDB2.php';
$article_id = 1; //if you fetch this parameter via GET/POST, remember to validate it!
//on passe le code de connexion DB
//on suppose qu'on a une connexion valide dans $db
$pager_options = array(
'mode' => 'Sliding',
'perPage' => 1, //On ne veut qu'un paragraphe par page
'delta' => 3,
);
$query = 'SELECT articles.title AS article_title,
articles.submission_date,
articles.abstract,
paragraphs.title AS paragraph_title,
paragraphs.content
FROM paragraphs
LEFT JOIN articles ON articles.id = paragraphs.article_id
WHERE articles.id = '. (int)$article_id .'
ORDER BY paragraphs.paragraph_id;
$paged_data = Pager_Wrapper_MDB2($db, $query, $pager_options);
//Afficher les résultats
echo '<h1>'.$paged_data['data'][0]['article_title'].'</h1>';
echo '<p><i>'.$paged_data['data'][0]['submission_date'].'</i></p>';
if ($paged_data['page_numbers']['current'] == 1) {
// afficher aussi le résumé.
echo '<p>'.$paged_data['data'][0]['abstract'].'</p>';
}
echo '<h2>'.$paged_data['data'][0]['paragraph_title'].'</h2>';
echo '<p>'.$paged_data['data'][0]['content'].'</p>';
//afficher les liens
echo $paged_data['links'];
?>
Puisque nous avons demandé au paginateur de couper les articles (les paragraphes, dans notre cas) en groupes de "un", il renverra seulement un paragraphe, et nous pouvons naviguer vers les autres paragraphes avec les liens générés par paginateur.
Voici le rendu du script :

Si vous n'aimez pas des liens normaux pour la navigation, et préférez un menu de <select> à la place, vous devez ajouter un appel à la la fonction getPageSelectBox () dans Pager_Wrapper_MDB2, avant de renvoyer le tableau de données paginée, puisqu'elle n'est pas incluse dans la version par défaut :
[php]
function Pager_Wrapper_MDB2(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = MDB2_FETCHMODE_ASSOC)
{
// Pager_Wrapper_MDB2() body omitted. Add the following lines before the return call:
// ===== Début du CODE ajouté ======
$selectbox_options = array(
'optionText' => 'page %d',
'autoSubmit' => true,
);
$page['select_menu'] = $pager->getPageSelectBox($selectbox_options);
// ===== Fin du CODE ajouté =====
return $page;
}
Maintenant on affiche le menu de navigation :
[php] <?php // [snip: même code que dans le paragraphe précédent] //Affichage du menu echo 'Choisissez une page: '. $paged_data['select_menu']; ?>
Et voilà ce que ca devrait donner:

Parfois, vous pouvez vouloir montrer un sommaire de l'article, avec une liste des titres de paragraphe, chacun indiquant le paragraphe complet.
Aucun problème, vous pouvez faire cela.
[php]
<?php
$query = 'SELECT title
FROM paragraphs
WHERE article_id = '. (int)$article_id
.' ORDER BY paragraph_id';
$paragraph_titles = $db->queryCol($query);
//on oublide le code de vérification
echo '<h2>Sommaire</h2>';
echo '<ul>';
foreach ($paragraph_titles as $k => $title) {
if ($k == ($paged_data['page_numbers']['current'] -1)) {
// Page courrante, ne pas afficher le lien
echo '<li>' . $title . '</li>';
} else {
echo '<li><a href="article.php?id='. (int)$article_id .'&pageID='. ($k+1) .'">'. $title . '</a></li>';
}
}
echo '</ul>';
?>
Le résultat est un résumé des titres de paragraphe, avec leurs liens

Si vous voulez proposer une version pour l'impression avec l'article complet, vous pouvez chercher tous les paragraphes et simplement les afficher l'un après l'autre :
[php]
<?php
$query = 'SELECT title,
submission_date,
abstract
FROM articles
WHERE id = '. (int)$article_id;
$article = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
$query = 'SELECT title,
content
FROM paragraphs
WHERE article_id = '. (int)$article_id
.' ORDER BY paragraph_id';
$paragraphs = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
//Afficher les données principales de l'article:
echo '<h1>'.$article['title'].'</h1>';
echo '<p><i>'.$article['submission_date'].'</i></p>';
echo '<p>'.$article['abstract'].'</p>';
// Afficher les paragraphes de l'article:
foreach ($paragraphs as $paragraph) {
echo '<h2>'.$paragraph['title'].'</h2>';
echo '<p>'.$paragraph['content'].'</p>';
}
?>
J'espère que ce tuto était utile (la traduc aussi :).
Si vous avez besoin de quelques clarifications, ou avez quelques suggestions , envoyez-nous un mail :
J'ai envie de m'intéresser à la Standard PHP Librairy. J'ai cherché quelques tutos et références.
Tuto& articles
références
Ce texte est une des traductions d'une série d'articles de Lorenzo Alberton
OK, vous ne pouvez pas résister à la tendance du Web 2.0 vous avez appris que tous que vous pourriez se renseigner sur cette « nouvelle » technologie appelée AJAX, et maintenant vous vous demandez comment vous pourriez vivre sans lui.
Tout le monde n'a pas sauté dans le mouvement, bien que, et beaucoup de bibliothèques existent toujours sans mettre en application ce dispositif, ainsi vous est confronté au dilemme :
Dois-je je continuer à employer que vieille bibliothèque et abandonner mes idées fraîches d'AJAX, ou devrais je mettre en application ma propre version ?
Si vous recherchez une classe de pagination avec ces conditions, je suis heureux de vous rassurer au sujet de PEAR::Pager : il est AJAX-ready, et a été depuis il y a longtemps.
garanti 100% buzzword-compliance !
D'abord, regardons un exemple simple sur la façon d'armer le paginateur pour créer des liens de Javascript.
Dans cet exemple plutôt simpliste, nous récupérons toutes les données dans les morceaux paginés, stockons chaque page dans un <div> et employons quelques scripting DOM pour cacher toutes les couches sauf la page courante.
[php]
<?php
require_once 'Pager/Pager.php';
$data = range(1, 100); //un tableau de données à paginer
$pager_params = array(
'mode' => 'Sliding',
'append' => false, //ne pas ajouter les paramètres GET
'path' => '',
'fileName' => 'javascript:revealDiv(%d)', //Pager replaces "%d" with the page number...
'perPage' => 10, //afficher 10 item par page
'delta' => 5,
'itemData' => $data,
);
$pager = & Pager::factory($pager_params);
$n_pages = $pager->numPages();
$links = $pager->getLinks();
?>
<html>
<head>
<script type="text/javascript">
var n_pages = <?php echo $n_pages ?>;
function revealDiv(n)
{
for (var count = 1; count <= n_pages; count++) {
document.getElementById("page"+count).style.display = 'none';
}
document.getElementById("page"+n).style.display = 'block';
}
</script>
<style type="text/css">
div.page {
background: #FFFF99;
border-top: 1px solid #FFBF99;
border-bottom: 1px solid #FFBF99;
}
</style>
</head>
<body>
<h1>PEAR::Pager exemple with JavaScript</h1>
<?php echo $links['pages']; ?>
<hr />
<?php
for ($i=1; $i <= $n_pages; ++$i) {
echo '<div class="page" id="page'.$i.'">';
echo '<h2>Page '.$i.'</h2>';
foreach ($pager->getPageData($i) as $item) {
echo 'Item '.$item.'<br />';
}
echo '</div>';
}
?>
<hr />
<script type="text/javascript">
revealDiv(1);
</script>
</body>
</html>
L'équipe de développement de PHP vient d'annoncer la sortie de PHP 4.4.9. Cette version a pour but d'améliorer la stabilité de la branche 4.4.x.
Parmi les correctifs on notera :
Une nouvelle version de MySQL vient de voir le jour. Cette nouvelle version apporte quelques modifications parmi lesquelles :
Lire un livre sur comment optimiser son site web c'est bien, appliquer les conseils qui s'y trouvent c'est encore mieux. Parmi les 14 bonnes pratiques, 3 peuvent être appliquées très rapidement au niveau système en quelques lignes de commande et de configuration du serveur web pour un résultat quasi immédiat :
Dans un premier temps, je vais m'intéresser à la règle 3, je suppose que vous avez déjà un serveur web Apache2 actif servant des fichiers (peu importe la technologie autour). La configuration suivante est utilisée sur ma Dedibox sous Ubuntu avec Apache2 mais doit pouvoir s'appliquer à peu près partout.
L'en-tête Expires indique quand un élément devra expirer du cache du navigateur; mettre une date d'expiration dans un futur lointain permet de maximiser l'utilisation du cache navigateur et donc d'éviter les téléchargements inutiles, ce qui est particulièrement utile pour les éléments statiques (images, feuilles de style, ...) qui ont tendances à changer ... peu fréquemment mais à ralentir l'affichage de la page si ils ne sont pas en cache. Pour ces éléments, il est possible de configurer l'expiration dans Apache avec le module expires . Pour les pages dynamiques ou éléments générés dynamiquement, c'est au script d'envoyer l'en-tête et sa valeur adéquate par exemple avec la fonction header() en PHP .
L'activation du module pour Apache2, il faut utiliser a2enmod avec la ligne suivante et ensuite recharger apache :
$ sudo a2enmod expires $ sudo /etc/init.d/apache2 reload
Il reste alors à configurer ce module. Je stocke la configuration de ce module dans le fichier /etc/apache2/conf.d/expires dont voici le détail :
ExpiresActive On ExpiresByType image/gif "access plus 30 days" ExpiresByType image/jpg "access plus 30 days" ExpiresByType image/jpeg "access plus 30 days" ExpiresByType image/png "access plus 30 days" ExpiresByType image/x-icon "access plus 30 days" ExpiresByType text/css "access plus 30 days" ExpiresByType application/x-javascript "access plus 30 days"
Tous les éléments statiques des types listés expirent 30 jours après leur premier téléchargement. Après un nouveau reload d'Apache, vous devriez voir apparaître l'en-tête Expires par exemple avec l'extension Firebug de Firefox au premier chargement des éléments de la page. Ensuite le navigateur utilisera son cache ce qui devrait accélérer l'affichage des pages suivantes utilisant les mêmes éléments.
Dotclear 2.0 est dès à présent disponible. Cette version apporte quelques nouveautés par rapport à la version 2.0 RC2.1 tel que :