Articles Taggés ‘PHP’

Importer des fichiers trop volumineux pour PHPmyAdmin

13 avril 2010

Si le fichier SQL que vous essayez d’importer est trop volumineux pour PhpMyAdmin, il vous reste la solution d’importer dans MySQL directement en ligne de commande.

mysql -D ma_base_de_donnees -u nom_Utilisateur -p mot_de_passe < mon_gros_fichier.sql

Vous ne passez plus par l’interface web et du coup vous ne serez pas limité.

Avant d’exécuter la commande placez vous,avec la commande cd, dans le dossier qui contient votre fichier mon_gros_fichier.sql. nom_Utilisateur et mot_de_passe correspondent à un utilisateur MySQL, vous pouvez paramétrer les droits de celui-ci (GRANT par exemple) dans privilèges dans l’interface PHPmyAdmin

Pour exécuter cette ligne de commande vous pouvez vous connecter sur le serveur Web avec Putty par exemple et pour mettre le fichier sur le serveur vous pouvez utiliser un client FTP comme fileZilla.

Eviter l’erreur : « __PHP_Incomplete_Class »

6 avril 2010

Si vous obtenez une erreur __PHP_Incomplete_Class lorsque vous utilisez des objets en session, c’est probablement parce que vous avez utilisé session_start() avant la déclaration de vos classes.
Par conséquent, attention à ce que la directive session.auto_start ne soient pas activée.

elephant-php

elephant-php

Vos rendez-vous Google Agenda lus par votre Nabaztag

2 avril 2010

Voilà mon script qui permet à votre lapin de lire vos évènements Google Agenda, est publié sur le site Zcripts : http://www.zcripts.com/zcript/nabgendaz-votre-nabaztag-devient-votre-agenda-google-de-poche-ou-presque
Pour comprendre comment ça marche regardez ici (La version publiée sur Zcripts est améliorée par rapport à celle que j’ai mis sur le blog, notamment pour la gestion des répétitions)

Google Calendar Nabaztag

Google Calendar Nabaztag

Les évènements Google Agenda dictés par votre Nabaztag (anniversaires, rdv etc…)

26 mars 2010

Si vous avez un compte Google Agenda et que vous souhaitez, que votre lapin vous rappelle les évènements du jour, voici un petit script pour vous.

A noter, que ce script sera bientôt disponible sur le site de zcripts.com pour que vous puissiez l’utiliser sans rien programmer, ni rien héberger ;)

Pour trouver l’adresse de votre fichier ical Google Calendar allez dans paramètres (en haut à droite) -> onglet Agendas -> cliquez sur le nom de l’agenda et descendez jusqu’à Adresse URL privée et cliquez enfin sur le bouton ical (vert)

ical_google_agenda

ical_google_agenda

$serial = "*********"; // serial de votre lapin
$token = "*********"; // token de votre lapin
// chemin privé de votre fichier ical privé de Google Agenda
$path = "***********";
// une partie de l'adresse est en dur pour éviter l'exécution d'un
// script distant
$fichier = "http://www.google.com/calendar/ical". $path ."basic.ics";

$source = file_get_contents($fichier); // on ouvre le fichier
$source = preg_split('#\n(?!s)#', $source);
$source = array_map('trim', $source);

$tabEve = array(); // tableau des évenements
$cles = array(); // tableau des clés des évenements

$i = 0;
// Boucle qui parcours le fichier à la recherche des événements
// le but est de dire que de l'index début à l'index fin on a un événement
foreach($source as $k=>$eve){  
// on récupère la zone pour gérer le décalage horaire
       if (eregi('X-WR-TIMEZONE',$eve)) {
        $ex = explode(":",$eve);
        $zone = $ex[1];
      }

    if ($eve == 'BEGIN:VEVENT') {
        $cles[$i]['debut'] = $k;
   }

   if ($eve == 'END:VEVENT') {
        $cles[$i]['fin'] = $k;
        $i++;
   }  
}

$e = 0;
// boucle qui va rechercher les évènements que l'on a délimité plus haut, et enfin on garde seulement les
// éléments nécessaires pour le lapin
foreach($cles as $c){
    for($eve=$c['debut']; $eve< =$c['fin'];$eve++){    
        $ex = explode(":",$source[$eve]);
        if(!isset($eves[$e][$ex[0]])){     
            if(eregi("SUMMARY",$ex[0]) || eregi("RRULE",$ex[0])){              
                $eves[$e][$ex[0]] = utf8_decode($ex[1]); // repetitions
            }
                       
            if(eregi("DTSTART",$ex[0])){
                $eves[$e]['SMOIS'] = substr($ex[1],4,2);
                $eves[$e]['SJOUR'] = substr($ex[1],6,2);
                $eves[$e]['SANNEE'] = substr($ex[1],0,4);
                $eves[$e]['DTSTART'] = substr($ex[1],0,4).substr($ex[1],4,2).substr($ex[1],6,2); // jour début
               

                              if(strlen($ex[1])>8){
                    $d = date('Y-m-d H:i',mktime(substr($ex[1],9,2), substr($ex[1],11,2),0, substr($ex[1],4,2), substr($ex[1],6,2), substr($ex[1],0,4)));
                    $date = new DateTime($d,new DateTimeZone($zone));
                    $new_date = strtotime($d)+$date->getOffset(); // calcul décalage horaire
                    $eves[$e]['HEURE'] = date('H:i',$new_date);
                }else{
                    $eves[$e]['HEURE'] = "";
                }

            }
            if(eregi("DTEND",$ex[0])){
                $eves[$e]['EMOIS'] = substr($ex[1],4,2);
                $eves[$e]['EJOUR'] = substr($ex[1],6,2);
                $eves[$e]['EANNEE'] = substr($ex[1],0,4);
                $eves[$e]['DTEND'] = substr($ex[1],0,4).substr($ex[1],4,2).substr($ex[1],6,2); // jour fin
            }
        }
    }
   
    $e++;
}

// Aujourd'hui
$jour = date("d"); // jour
$mois = date("m"); // mois
$annee = date("Y"); // annee
$aujourdhui = date("Ymd"); // date du jour

// création du tableau final qui récupère les évènements du jour (aussi ceux qui in une fréquence annuelle pour les anniversaires par exemple)
if(count($eves)>0){
foreach($eves as $eve){
   
        if(empty($eve['HEURE'])){$eve['HEURE'] = " ";}else{$eve['HEURE'] = " à " . $eve['HEURE'];}

   
    if($aujourdhui>=$eve['DTSTART'] && $aujourdhui< =$eve['DTEND']){
                $tabEve[] = $eve['SUMMARY']. $eve['HEURE'];
               
    }else{
        if(eregi("FREQ=YEARLY",$eve['RRULE'])){
           
            $d = $annee.substr($eve['DTSTART'],4,4);
           
            if($aujourdhui>=$d && $aujourdhui<=$d){
                $tabEve[] = $eve['SUMMARY']. $eve['HEURE'];
               
            }
        }
    }

}
}
// Maintenant que nous avons le tableau tabEve des évènements du jour, on peut créer le texte du lapin

$phrase = "évènements du jour : ";
foreach($tabEve as $evefin){
    $phrase .= $evefin. " . ";
}
if(empty($phrase)){
    $phrase = "Rien aujourd'hui";  
}

// envoi au lapin !
$curl = curl_init();
$api_url = "http://api.nabaztag.com/vl/FR/api.jsp?&sn=$serial&token=$token&voice=$voice&tts=".urlencode(utf8_encode($phrase));
curl_setopt($curl,CURLOPT_HEADER,$api_url);
curl_exec($curl);
curl_close($curl);

}

Voilà. Ce script pourrait être amélioré, avec la gestion des autres répétitions, MONTHLY etc…

Créez votre module personnalisé d’expédition Joomla Virtuemart

20 mars 2010

Si vous avez besoin de créer un module d’expédition personnalisé pour Joomla Virtuemart, voici quelques informations pour vous aider.

(Pour info, pour installer VirtueMart sur Joomla, il suffit de télécharger Virtuemart, vous dezippez l’archive, puis vous vous connectez en administrateur sur joomla, vous allez dans le menu extensions puis installer/desinstaller
et vous uploadez/installez le fichier virtuemart.zip)

Fichiers de base

Il y a 3 fichiers de bases pour créer un module d’expédition, que vous devrez placer dans :
/administrator/components/com_virtuemart/classes/shipping/
Une classe, un fichier d’information et un fichier de configuration.
Si vous voulez créer un module s’appelant expPerso nommez les fichiers ainsi :

  • expPerso.php (la classe expPerso)
  • expPerso.ini (versionning du module, créateur etc…)
  • expPerso.cfg.php (constantes de configuration du module)

Récupérez les 3 fichiers du module de base, renommez les et adaptez les… ;)

Une fois ces 3 fichiers placés, vous pourrez activer votre module dans composant -> VirtueMart -> configuration -> onglet shipping
virtuemart

Gérer les traductions

La page qui gère les traductions de l’interface d’ajout des taux d’expédition est :
/www/administrator/components/com_virtuemart/languages/shipping/french.php
Pour les erreurs, par exemple si un champs n’a pas été rempli, regardez le fichier
/www/administrator/components/com_virtuemart/languages/common/french.php

Créer de nouveaux taux

Le formulaire qui gère la création de nouveaux taux est :
/www/administrator/components/com_virtuemart/html/shipping.rate_form.php

Fichiers d’ajouts de taux

Les classes de fonctionnement sont :
/www/administrator/components/com_virtuemart/classes/ps_shipping.php qui contient les fonctions qui gèrent l’ajout/modification/suppression des taux
/www/administrator/components/com_virtuemart/html/shipping.rate_form.php qui est le formulaire html d’ajout (interaction avec ps_shipping.php)
/www/administrator/components/com_virtuemart/html/shipping.rate_list gère l’affichage des taux ajoutés.
Dans ce fichier, les entêtes sont gérés par le tableau $columns

$columns = Array(  "#" => "width=\"20\"",
    "<input type=\"checkbox\" name=\"toggle\" value=\"\" onclick=\"checkAll(".$num_rows.")\" />" => "width=\"20\"",
    $VM_LANG->_('PHPSHOP_SHIPPING_RATE_LIST_CARRIER_LBL') => '',
    $VM_LANG->_('PHPSHOP_SHIPPING_RATE_LIST_RATE_NAME') => '',
        $VM_LANG->_('E_REMOVE') => "width=\"5%\""
);

Et les cellules par l’objet $listObj

$listObj->addCell( $db->f("shipping_rate_value"));

Notez que les constantes, qui sont donc par convention en majuscules comme PHPSHOP_SHIPPING_RATE_LIST_CARRIER_LBL sont traduites grâce aux fichiers de traduction que j’ai présenté plus haut, alors que $db->f(« shipping_rate_value ») correspond à un champ en base de données

La classe expPerso

Au début je vous ai parlé de expPerso.php qui contient la classe expPerso. Ce fichier contient la requête qui après validation de la commande affiche les possibilités d’expéditions.

exemple un morceau de la requête qui affiche un les frais d’expédition en fonction du poids de la commande

$q .= "shipping_rate_weight_start < = '" . $d["weight"] . "'AND " ;
$q .= "shipping_rate_weight_end >= '" . $d["weight"] . "'" ;

Pour utiliser le montant de la commande appelez tout simplement la variable globale $total

function list_rates( &$d ) {
    global $total;
[...]

Le code postal, lui par exemple est déjà récupéré par la requête

$zip = $dbc->f( "zip" ) ;

Bon, voilà de quoi vous éclairer un peu, maintenant à vos claviers pour faire vos modifications…

Installer PHP sous Ubuntu, soit LAMP (Linux Apache MySQL PHP)

12 mars 2010

Installation de l’environnement

Pour développer en local du PHP, vous aurez besoin d’installer Apache, MySQL et PHP.
Tapez dans un terminal :

sudo tasksel install lamp-server

Il est conseillé de mettre un mot de passe pour MySQL
Une fois que c’est fait, vous pouvez tester le serveur en entrant l’adresse suivante dans votre navigateur préféré : http://127.0.0.1 ou http://localhost/

Si vous voyez ce message :

It works!
This is the default web page for this server.
The web server software is running but no content has been added, yet.

c’est que tout s’est bien passé.

Changer de répertoire de travail

Par défaut, la page web que vous voyez se trouve dans

/var/www

Ce qui n’est pas très pratique, car par défaut vous n’avez pas les droits en écriture sur ce dossier qui appartient à ROOT.

Puisqu’on ne va pas l’utiliser rendons ce dossier inaccessible de l’extérieur.

sudo gedit /etc/apache2/sites-available/default

Recherchez le bloc délimité par <Directory /var/www/> et </Directory/>et remplacez-le contenu par :

<directory /var/www>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride None
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1       
</directory>

Ajoutez également Allow from 192.168.0.0/24 si vous voulez y accéder de votre réseau local, si vos adresses IP local sont en 192.168.1.0, adaptez évidemment.

Ouvrez ensuite le fichier httpd.conf

sudo gedit /etc/apache2/httpd.conf

Et ajoutez cette ligne

ServerName localhost

On va maintenant activer l’option userdir, qui va permettre d’activer un dossier de développement pour chaque utilisateur.

mkdir /home/$USER/public_html
sudo a2enmod userdir

On redémarre Apache, pour que les modifications soient prises en compte.

sudo /etc/init.d/apache2 force-reload

Voilà, maintenant le dossier public_html qui se trouve dans votre espace de travail est accessible via http://127.0.0.1/~yann
Remplacez évidemment yann par votre nom d’utilisateur
pour tester, créez un nouveau fichier test.php dans le dossier public_html et copiez-y ce code

<?php
    echo phpinfo();
?>

Ouvrez l’URL http://127.0.0.1/~yann/test.php, vous devriez voir la configuration PHP s’afficher. Si votre navigateur télécharge les fichiers au lieu de les interpréter, regardez la fin de cet article…

Installer phpMyAdmin

Téléchargez l’archive de phpMyAdmin et décompressez là. Renommez ensuite le dossier en phpMyAdmin puis déplacez le dans /var/www

sudo mv phpMyAdmin/ /var/www/phpMyAdmin

phpMyAdmin utilise le module mcrypt, alors installons-le

sudo apt-get install php5-mcrypt

On redémarre Apache

sudo /etc/init.d/apache2 force-reload

Et voilà phpMyAdmin est accessible à l’adresse http://127.0.0.1/phpMyAdmin
Connectez vous avec root : mot_de_passe_que vous avez_choisi

Où est mon php.ini ?

Le fichier de configuration de PHP se trouve dans /etc/php5/apache2/php.ini pour désactiver short_open_tag et magic_quotes_gpc par exemple, ce qui serait une très bonne idée ;)
N’oubliez pas de relancer Apache

sudo /etc/init.d/apache2 force-reload

Mon navigateur télécharge les fichiers PHP au lieu de les interpréter :(

Sous Ubuntu 10.04, php est désactivé quand vous utilisez le module a2enmod. Pour éviter que le navigateur télécharge les fichiers php, éditez le fichier

sudo gedit /etc/apache2/mods-enabled/php5.conf

Et commentez les lignes ci dessous :

#<ifmodule mod_userdir.c>
#   <directory /home/*/public_html>
#       php_admin_value engine Off
#  </directory>
#</ifmodule>

Et on relance apache…

sudo /etc/init.d/apache2 force-reload

Si vous recherchez des conseils pour la certification PHP 5

Alterner les couleurs des lignes d’un tableau (PHP ou jQuery)

9 mars 2010

Pour faciliter la lecture d’un tableau il est fréquent d’alterner la couleur de chaque ligne.
Le principe est d’attribuer aux lignes paires un style et un autre aux lignes impaires.

En PHP

Voir la démo
Créons tout d’abord 2 styles.

.style1{
    background-color : #F2F1EB;
}
.style2{
    background-color : #DAE9F4;
}

En PHP on utilise le modulo % (reste de la division) . Le modulo d’une division par 2 permet de savoir si la ligne est paire ou impaire, il ne reste plus qu’à affecter un style pour chacun des 2 cas.

echo "<table class='monTab'>";
    for($i=1; $i < = 10; $i++){
           
        if($i%2){
            $classe = "style1";
        }else{
            $classe = "style2";
        }
       
        echo  "<tr class='$classe'>
                        <td>ligne $i</td>
                        <td>ligne $i</td>
                  < /tr> "
;
    }
echo "</table>";

On affecte à la variable $classe l’un ou l’autre des styles et on l’applique à la ligne.

En jQuery

Voir la démo
Partons du même tableau.

echo "<table class='monTab'>";
    for($i=1; $i < = 10; $i++){
   
        echo  "<tr>
                <td>ligne $i</td>
                <td>ligne $i</td>
                < /tr> "
;
    }
echo "</table>";

et appliquons un style différent selon que les lignes soient paires (even) ou impaires (odd)

$(document).ready(function(){
    $('table.monTab tr:nth-child(even)').addClass('style1');
    $('table.monTab tr:nth-child(odd)').addClass('style2');
});

On applique donc le style style1 à chaque ligne paire (even) et le style2 à chaque ligne impaire (odd) du/des tableau(x) dont la classe est monTab grâce à la méthode addClass de jQuery, qui ajoute une classe à un élément.

L’utilisation de nth-child permet d’éviter que jQuery se perde si vous avez plusieurs tableaux dans votre page, en effet sinon il continu d’attribuer les couleurs sans repartir à zéro. Ainsi la première ligne du tableau 1 pourrait être bleue alors que la première ligne du tableau 2 serait blanche.

Numéro de téléphone avec des points et conversion de date en français avec PHP

8 mars 2010

Téléphone

Lorsque vous demandez à un visiteur de saisir son numéro de téléphone, il est plus simple pour lui de le taper sans utiliser de points ou d’espaces etc… Pourtant lorsque vous l’affichez c’est quand même plus lisible que les chiffres ne soient pas tous collés.
Une possibilité, consiste à utiliser wordwrap

$tel = "0145666666";
$tel_formate = wordwrap ($tel, 2, '.', 1); // 01.45.66.66.66

string wordwrap ( string str , int width , string break , bool cut )
wordwrap retourne la chaîne str , après avoir inséré break tous les width caractères.

Convertir une date au format français

Si vous récupérez une date issue de votre base mysql par exemple, le format sera YYYY-MM-DD, cependant pour l’afficher à l’écran les français préféreront une date au format JJ/MM/AAAA.
Une solution consiste à utiliser preg_replace qui recherche et remplace par expression rationnelle.

$maDate = preg_replace('/^(.{4})-(.{2})-(.{2})$/','$3/$2/$1', $maDate );

mixed preg_replace ( mixed pattern , mixed replacement , mixed subject , int limit , int count )
preg_replace analyse subject pour trouver l’expression rationnelle pattern et remplace les résultats par replacement

Téléphone 2

On peut aussi modifier le numéro de téléphone avec preg_replace.
Avec par exemple :

$tel = preg_replace("/(\d{2}) *(?!\z)/","$1.",$tel);

NB : pour wordwrap comme pour l’exemple ci-dessus, on n’a pas vérifié la taille de la chaine !

Nabaztag et Google Reader (OPML)

7 mars 2010

Voici un petit script permettant à votre lapin de vous donner les dernières news provenant de l’ensemble de vos flux Google Reader.
Vous pouvez tester le résultat ici

Parser le fichier OPML

Pour cela, nous allons parser le fichier OPML que vous pouvez récupérer en cliquant sur Gérer mes abonnements (tout en bas à gauche de votre interface Google Reader) puis Importer/Exporter et enfin Exporter vos abonnements.

D’abord il faut extraire les différents flux du fichier OPML, pour cela j’ai créé une fonction recupFlux récursive.

// Flux google reader
$url_flux_rss = "http://*******/google-reader-subscriptions.xml"; // à remplacer évidemment
$tabFlux = array();
$tabNewRSS = array();

function recupFlux($xml,$prof=1) {
    global $tabFlux;
        foreach($xml->children() as $child) {
            if (isset($child['xmlUrl'])) {
                $tabFlux[] = $child['xmlUrl'];
            }
            recupFlux($child,$prof+1);
        }

}
$opml= new SimpleXMLElement($url_flux_rss,null,true);
recupFlux($opml->body);

Vous obtenez ainsi un tableau $tabFlux contenant tous les flux.

Ensuite vous pouvez aller chercher chacune des 2 dernières news de chaque flux (par exemple).

foreach($tabFlux as $flux){
    // recup des 2 dernières infos de chaque flux
    $limite       = 2; // nombre d'actus à afficher

    $Xml = @simplexml_load_file($flux); // charge le fichier
        if($Xml === false){
           die("Erreur Flux, vérifiez l'adresse du flux");
        }

    $i = 0;
    foreach ($Xml->channel->item as $mon_rss){
        $titre = (string) utf8_decode($mon_rss->title);
        $quand = (string) utf8_decode($mon_rss->pubDate);
        $i++;

        $tabNewRSS[strtotime($quand)] = $titre; // on créé un nouveau tableau
        if($i >= $limite){
             break;
        }
    }

}
krsort($tabNewRSS); // trie le tableau pour avoir les dernières news dans l'ordre tous flux confondus

J’ai mis en clé du tableau le timestamp de la publication de la news (dans l’absolu, si 2 news avaient la même date la 2ème écraserait l’autre…)

Parle mon lapin

Il ne reste plus qu’à donner la parole à votre lapin, comme vu dans l’article précédent

include('nabClass.php');
$serial = "****";
$token = "****";

$nabaztag = new nabaztag($serial,$token);
$phrase = "";
foreach($tabNewRSS as $final){
    $phrase .= $final.". ";
}

$phrase = html_entity_decode($phrase);

if ($phrase){
    $nabaztag->speak(utf8_encode($phrase));
}

$nabaztag->display_api_response();

Vous pouvez tester le résultat ici
A noter que ce script envoi à votre Nabaztag les infos à un instant T, mais on pourrait très facilement recréer un nouveau fichier RSS à partir de $tabNewRSS pour le soumettre à l’interface de Violet, ainsi votre Lapin vous tiendrait au courant au fur et à mesure des nouvelles informations…

Générer un nouveau flux RSS

Le but est de soumettre à l’interface de violet la page qui va générer le flux RSS qui mixe les flux de notre Google Reader.
Première chose, indiquez que le résultat sera du XML, avec la balise Header

header("Content-Type: text/xml;charset=utf-8");

Ensuite, au lieu d’envoyer le texte au Nabaztag, nous allons générer un flux RSS à partir du tableau $tabNewRSS que nous avons créé ci-dessus.

$rss = '< ?xml version="1.0" encoding="utf-8"?>';
    $rss .= '<rss version="2.0">';
    $rss .= "<channel>";
    $rss .= "<title>Mon Google Reader RSS</title>";
    $rss .= "<link>http://blog.yann.info</link>";
    $rss .= "<description>Compilation de mes flux Google Reader</description>";
    $rss .= "<language>fr-FR</language>";
   
        foreach($tabNewRSS as $final){
            $rss .= "<item>";      
            $rss .= "<title>" . clean($final) . "</title>";
            $rss .= "<link>http://blog.yann.info</link>";
            $rss .= "<pubdate>".date("D, d M Y H:i:s")."</pubdate>";
            $rss .= "<description></description>";
            $rss .= "</item>";
        }
       
    $rss .= "</channel>";
    $rss .= "</rss>";
    echo $rss;

Pour voir un exemple de ce que ça peut donner cliquez ici
Le résultat est un nouveau flux RSS, que vous pouvez soumettre à l’interface Violet. Les news sont à chaque fois régénérées donc votre lapin ne vous donnera que les dernières news dès qu’il y aura du nouveau.
Comme le lapin ne lira que le titre du RSS je n’ai rempli que cette partie dynamiquement.

function clean($titre) {
    return utf8_encode(htmlspecialchars(stripslashes($titre)));
}

Mysql : ON DUPLICATE KEY UPDATE

4 mars 2010

Une petite clause bien pratique : ON DUPLICATE KEY UPDATE.
Imaginez que vous vouliez mettre à jour un enregistrement dans votre base dans le cas ou celui ci existe déjà et sinon, s’il n’existe pas, en créer un nouveau. Une solution serait de faire un SELECT sur la clé, et soit un UPDATE ou un INSERT selon que la clé existe ou non. Une autre solution serait de faire un UPDATE et si mysql_affected_rows == 0 alors vous faites un INSERT… Pourquoi pas.

Mais MySQL permet de faire tout ça en une seule requête !

INSERT INTO maTable (id_table,champ_table)
VALUES ('152','valeur à modifier')
ON DUPLICATE KEY UPDATE
champ_table='valeur à modifier';

Bien entendu, pas besoin de mettre de WHERE dans la partie UPDATE vu que c’est parce que la clé existe que le update est exécuté

A noter que ON DUPLICATE KEY UPDATE est différent de REPLACE qui s’apparente plutôt à un DELETE + INSERT qui oblige à donner une valeur à tous les champs, alors qu’avec ON DUPLICATE KEY UPDATE on ne spécifie que les champs qui sont à modifier.