<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hooba Studios &#187; SQL</title>
	<atom:link href="http://www.hooba.ca/blog/categorie/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hooba.ca/blog</link>
	<description></description>
	<lastBuildDate>Sun, 11 Jul 2010 13:51:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MongoDB et autres bases de données NoSQL, le début d&#8217;une nouvelle ère</title>
		<link>http://www.hooba.ca/blog/2009/mongodb-et-autres-bases-de-donnees-nosql-le-debut-dune-nouvelle-ere/</link>
		<comments>http://www.hooba.ca/blog/2009/mongodb-et-autres-bases-de-donnees-nosql-le-debut-dune-nouvelle-ere/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 16:39:45 +0000</pubDate>
		<dc:creator>Antoine Leclair</dc:creator>
				<category><![CDATA[Environnement]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.hooba.ca/blog/?p=409</guid>
		<description><![CDATA[Depuis le printemps dernier, on entend parler de plus en plus du mouvement NoSQL. Pour ceux qui auraient eu la tête dans le sable pendant les derniers mois, il s&#8217;agit d&#8217;un mouvement qui cherche à trouver d&#8217;autres solutions pour la gestion des données que les RDBMS (bases de données relationnelles, à la MySQL / SQL [...]]]></description>
			<content:encoded><![CDATA[<p>Depuis <a href="http://nosql.eventbrite.com/">le printemps dernier</a>, on entend parler de plus en plus du mouvement NoSQL. Pour ceux qui auraient eu la tête dans le sable pendant les derniers mois, il s&#8217;agit d&#8217;un mouvement qui cherche à trouver d&#8217;autres solutions pour la gestion des données que les <a href="http://en.wikipedia.org/wiki/RDBMS">RDBMS</a> (bases de données relationnelles, à la MySQL / SQL Server). C&#8217;est donc le retour en force des bases de donnée <em>key/value pair</em> et autres formes de bases de données sans schéma.<span id="more-409"></span></p>
<h3>Les problèmes des RDBMS</h3>
<p>Les bases de données relationnelles ont comme caractéristique principale d&#8217;être très structurées. C&#8217;est sans doute la raison derrière leur grande popularité. Par contre, ce ne sont pas tous les problèmes qui tombent dans le moule de ce type d&#8217;architecture.</p>
<p>Aussi, il devient plutôt difficile, dépassé un certain point, de continuer à <em>scaler</em> horizontalement avec ce type de bases de données. On met la base de donnée sur un autre serveur, ensuite on ajoute des réplications pour avoir des master/slaves, on optimise nos requêtes&#8230; ça peut nous mener très loin, mais pas assez loin pour les gros joueurs. Le problème des performances était donc aussi une des motivations pour chercher une autre solution.</p>
<h3>The new kids on the block</h3>
<p>Alors voilà qu&#8217;apparait toutes les nouvelles bases de données et que le sujet se met à bouillonner. <a href="http://1978th.net/">Tokyo</a>, <a href="http://couchdb.apache.org/">CouchDB</a>, <a href="http://www.mongodb.org/">MongoDB</a>, <a href="http://hadoop.apache.org/hbase/">HBase</a> (du projet <a href="http://hadoop.apache.org/">Hadoop</a>), <a href="http://code.google.com/p/redis/">Redis</a>, <a href="http://incubator.apache.org/cassandra/">Cassandra</a>, etc.</p>
<p>Ces projets sont pour la plupart orienté sur la distributivité de la base de donnée. Elles ont été conçues à la base pour <em>scaler</em> horizontalement.</p>
<h3>Essai de MongoDB avec PHP</h3>
<p>J&#8217;ai donc décidé d&#8217;essayer un de ces systèmes: <a href="http://www.mongodb.org/">MongoDB</a>. Il s&#8217;agit d&#8217;une base de donnée sans schéma: on y stock les données à peu près comme on veut et chaque entrées peut avoir des champs différents. L&#8217;installation est plutôt simple (du moins sous Linux), <a href="http://www.mongodb.org/display/DOCS/Downloads">les fichiers binaires ou le code source</a> sont disponible sur le site web. Lorsque le serveur est installé, il faut installer les <em>drivers</em> pour chaque langage que l&#8217;on compte utiliser (PHP, Python, Ruby, Java, etc. C++, lui, est inclu). J&#8217;ai donc installé le <em>driver</em> pour PHP à partir du <a href="http://www.mongodb.org/display/DOCS/Installing+the+PHP+Driver">code source sur le site web</a>. Seulement ensuite je me suis rendu compte que j&#8217;aurais pu me sauver un peu de compilation en faisant simplement <code>sudo pecl install mongo</code> (sous Ubuntu).</p>
<p>Voici un exemple de code <a href="http://www.mongodb.org/display/DOCS/PHP+Tutorial">tiré à peu près du site de MongoDB</a> pour insérer des données:</p>
<pre><code>$m = new Mongo();
$collection = $m->selectDB( "foo" )->selectCollection( "bar" );

$doc = array( "name" => "MongoDB",
   "type" => "database",
   "count" => 1,
   "info" => (object)array( "x" => 203,
       "y" => 102),
   "versions" => array("0.9.7", "0.9.8", "0.9.9")
);

$collection->insert( $doc );</code></pre>
<p>On les récupère ensuite:</p>
<pre><code>$m = new Mongo();
$collection = $m->selectDB( "foo" )->selectCollection( "bar" );

$obj = $collection->findOne();
</code></pre>
<p>Ou on peut faire une requête pour plusieurs résultats:</p>
<pre><code>$m = new Mongo();
$collection = $m->selectDB( "foo" )->selectCollection( "bar" );

$cursor = $collection->find( array('name' => 'MongoDB') );

while( $cursor->hasNext() ) {
    var_dump( $cursor->getNext() );
}</code></pre>
<h3>Simple, trop simple?</h3>
<p>Avec les bases de données relationnelles, le simple apprentissage du SQL permettait de bien comprendre le paradigme des RDBMS et de bien s&#8217;en servir. Maintenant, avec les nouvelles bases de données qui apparaissent, nous avons beaucoup plus de flexibilité: on y met à peu près ce qu&#8217;on veut. Le prochain objet qu&#8217;on y insère n&#8217;a pas besoin de ressembler au précédent. Cette flexibilité est bienvenue et très puissante (par exemple, on peut faire rouler plusieurs version de la même application en même temps, selon le client, avec la même base de donnée, comme Google le fait avec Gmail).</p>
<p>Cette flexibilité et simplicité vient par contre au prix d&#8217;être complètement laissés à nous-même. Les RDBMS sont vieilles et son fonctionnement bien connu de tous. Des tonnes de livres ont été écrites sur MySQL, SQLite, SQL Server et l&#8217;architecture avec les RDBMS. Les fonctionnalités des nouvelles bases de données sont généralement bien documentées. C&#8217;est très simple (beaucoup plus simple qu&#8217;avec du SQL) d&#8217;y insérer et récupérer des entrées. Par contre, la façon de penser l&#8217;architecture d&#8217;applications qui utilisent ces bases de données est plutôt nébuleuse. Je n&#8217;ai pas encore vu de livre qui traitent de l&#8217;utilisation de ces systèmes et les blogs qui en glissent un mot parlent plutôt de l&#8217;architecture matérielle utilisée, des raisons qui ont poussés la migration et des raisons de leur choix particulier parmi les nouvelles bases de données.</p>
<h3>On va continuer d&#8217;en entendre parler</h3>
<p>Ceci dit, tout ce que j&#8217;ai lu à date sur le sujet est très positif. Est-ce révolutionnaire ou bien avait-on simplement besoin d&#8217;air frais? Une chose est sûr c&#8217;est que les bases de données &laquo;&nbsp;non-relationnelles&nbsp;&raquo; sont là pour rester. Par contre, elles n&#8217;écraseront pas les RDBMS pour toutes les situations de si tôt: elles ne sont pas (et ne tentent pas d&#8217;être) <a href="http://en.wikipedia.org/wiki/ACID">ACID</a>. On continuera donc sans doute à utiliser les RDBMS pour les utilisations comme les transactions financières, où l&#8217;intégrité des données et l&#8217;utilisation de transactions (dans le sens SQL du terme) sont importantes.</p>
<p>Encore faut-il que nos universités abordent le sujet. Parions qu&#8217;ils n&#8217;en parleront pas avant un bon 10 ans!</p>
<p>Si vous connaissez une source (livre, blog, wiki, etc.) où on peut en apprendre sur la conception d&#8217;application et d&#8217;architecture avec ces nouvelles bases de données, laissez-moi savoir!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hooba.ca/blog/2009/mongodb-et-autres-bases-de-donnees-nosql-le-debut-dune-nouvelle-ere/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bon code, Bad code</title>
		<link>http://www.hooba.ca/blog/2009/bon-code-bad-code/</link>
		<comments>http://www.hooba.ca/blog/2009/bon-code-bad-code/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 03:19:15 +0000</pubDate>
		<dc:creator>Antoine Leclair</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Sécurité]]></category>
		<category><![CDATA[Théorie]]></category>

		<guid isPermaLink="false">http://www.hooba.ca/blog/?p=384</guid>
		<description><![CDATA[Il n&#8217;y a pas si longtemps, j&#8217;ai eu à intégrer du code PHP qu&#8217;un autre programmeur avait déjà fait pour un autre site. Le client tenait à ce que j&#8217;utilise son &#171;&#160;module&#160;&#187; de nouvelles en pensant sauver de l&#8217;argent. La première fois que j&#8217;ai eu à intégrer ledit module, ç&#8217;a effectivement été plutôt rapide étant [...]]]></description>
			<content:encoded><![CDATA[<p>Il n&#8217;y a pas si longtemps, j&#8217;ai eu à intégrer du code PHP qu&#8217;un autre programmeur avait déjà fait pour un autre site. Le client tenait à ce que j&#8217;utilise son &laquo;&nbsp;module&nbsp;&raquo; de nouvelles en pensant sauver de l&#8217;argent. La première fois que j&#8217;ai eu à intégrer ledit module, ç&#8217;a effectivement été plutôt rapide étant donné que le site était fait dans le même <em>pattern</em> que le site d&#8217;origine. Par contre, la deuxième fois, c&#8217;était une toute autre chose!<span id="more-384"></span></p>
<h3>Du code non-réutilisable</h3>
<p>J&#8217;espère ne rendre personne triste en publiant cet article, mais je vais vous faire un petit copier-coller d&#8217;une fonction pour illustrer mes points.</p>
<pre>&lt;?php
// _______________________________________________________________________
// Display news list
function fct_display_news_list(){
    // Search
    if(isset($_GET['search']) &amp;&amp; !empty($_GET['search'])){
        $query = " WHERE title LIKE CONVERT(_utf8 '%".$_GET['search']."%' USING latin1) OR content LIKE CONVERT(_utf8 '%".$_GET['search']."%' USING latin1)";
    }else{
        if(isset($_GET['date']) &amp;&amp; ereg("^[0-9]{4}\-[0-9]{2}$", $_GET['date'])){
            $arr = explode("-", $_GET['date']);
            $date_start = mktime(0, 0, 0, $arr[1], 1, $arr[0]);
            $date_end = mktime(0, 0, 0, $arr[1] + 1, 1, $arr[0]);
            $query = " WHERE date_news&gt;=".$date_start." AND date_news&lt;".$date_end;
        }
    }
    if(!isset($query)){
        $query = " ORDER BY date_news DESC LIMIT 3";
    }else{
        $query .= " ORDER BY date_news DESC";
    }

    $query = "SELECT * FROM juris_news".$query;
    $result = mysql_query($query) or die(mysql_error());
    if(mysql_num_rows($result) &gt; 0){
        for($i = 1; $row = mysql_fetch_array($result); $i++){
?&gt;
    &lt;h3 first"); } ?&gt;"&gt;&lt;?= $row['title']; ?&gt;&lt;/h3&gt;
    &lt;p&gt;&lt;?= date("Y-m-d", $row['date_news']); ?&gt;&lt;/p&gt;
    &lt;p&gt;&lt;?= $row['intro']; ?&gt;&lt;/p&gt;
    &lt;p&gt;&lt;a href="actualites.php?id=&lt;?= $row['id']; ?&gt;" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('news&lt;?= $i; ?&gt;','','medias/img_c_btn_savoir_rl.gif',0)"&gt;&lt;img src="medias/img_c_btn_savoir_up.gif" alt="En savoir plus" name="news&lt;?= $i; ?&gt;" id="news&lt;?= $i; ?&gt;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;?php
        }
    }else{
        echo("&lt;p&gt;Aucune actualit&amp;eacute; trouv&amp;eacute;e.&lt;/p&gt;");
    }
}</pre>
<p>Il s&#8217;agit ici de la première fonction d&#8217;une dizaine de fonctions similaires qui constituent le fichier.</p>
<h3>Premier péché: mélanger la logique avec la présentation</h3>
<p>La principale force de PHP est aussi sa principale faiblesse: il est très facile de mélanger du PHP avec du HTML. On peut avoir une page entière en HTML et y insérer très facilement un peu de PHP. On peut par contre aussi avoir du PHP et y insérer du HTML. Le problème avec cette fonction, c&#8217;est qu&#8217;elle génère (et affiche) du HTML.</p>
<p>On peut voir très facilement que le code HTML affiché n&#8217;est pas réutilisable. Il y a des appels à des fonctions JavaScript et des images dont le chemin d&#8217;accès est <em>hard coded</em>. Par exemple, la fonction affiche:</p>
<pre><code>// mauvais
</code>&lt;p&gt;&lt;a href="actualites.php?id=&lt;?= $row['id']; ?&gt;" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('news&lt;?= $i; ?&gt;','','medias/img_c_btn_savoir_rl.gif',0)"&gt;&lt;img src="medias/img_c_btn_savoir_up.gif" alt="En savoir plus" name="news&lt;?= $i; ?&gt;" id="news&lt;?= $i; ?&gt;" /&gt;&lt;/a&gt;&lt;/p&gt;</pre>
<p>Il est fort peu probablement que j&#8217;aie à utiliser les mêmes fonctions JavaScript et que j&#8217;utilise les mêmes images. Aussi, le <em>markup</em> HTML généré ne conviendra générallement pas aux besoins d&#8217;un autre site. Par exemple, je doute que <code>&lt;h3 class="blue"&gt;</code> puissent être réutilisé.</p>
<p>La meilleur façon aurait été de simplement arrêter la fonction à la fin de la requête SQL. La fonction aurait simplement pu retourner un <em>array</em>, un objet ou un itérateur. De cette manière, on sépare la logique de la présentation. Par exemple, si la fonction retournait un <em>array</em> <code>$nouvelles</code>, on pourrait l&#8217;intégrer dans la page directement.</p>
<pre><code>&lt;!-- Mieux --&gt;
&lt;!-- Markup de ce qui vient avant dans la page ici... --&gt;
&lt;div id="nouvelles"&gt;
    &lt;h2&gt;Nouvelles&lt;/h2&gt;
    &lt;?php if (!empty($nouvelles)) : ?&gt;
    &lt;?php foreach ($nouvelles as $nouvelle) : ?&gt;
    &lt;p class="date"&gt;&lt;?= date("Y-m-d", $nouvelle['date_news']) ?&gt;&lt;/p&gt;
    &lt;p&gt;&lt;?= $nouvelle['intro'] ?&gt;&lt;/p&gt;
    &lt;p&gt;&lt;a href="actualites.php?id=&lt;?= $nouvelle['id']; ?&gt;" class="more"&gt;En savoir plus&lt;/a&gt;&lt;/p&gt;
    &lt;?php endforeach ?&gt;
    &lt;?php else : ?&gt;
    &lt;p&gt;Aucune nouvelle&lt;/p&gt;
    &lt;?php endif ?&gt;
&lt;/div&gt;
&lt;!-- Suite du site ici... --&gt;
&lt;div id="sidebar"&gt;</code></pre>
<h3>Deuxième péché: La fonction n&#8217;accepte aucun paramètre</h3>
<p>De la façon dont la fonction est codée, on n&#8217;a aucun moyen externe (lire: aucun paramètre) d&#8217;affecter son déroulement. Si <code>$_GET['search']</code> contient quelque chose, une recherche sera faite, sinon, les trois dernières nouvelles sont affichées.</p>
<p>Il serait bien de pouvoir appeler la fonction en lui demandant un certain nombre de nouvelles. Je ne veux pas avoir toujours les trois dernières nouvelles dans tous les sites que je dois faire.</p>
<p>Aussi, si je veux faire une recherche, je ne veux pas nécessairement utiliser <code>$_GET['search']</code> comme chaine à chercher.</p>
<p>Le prototype de cette fonction aurait plutôt dû ressembler à ceci:</p>
<pre><code>function fct_display_news_list($quantity = 3, $search = NULL)</code></pre>
<p>De cette manière, on aurait pu avoir des comportements par défaut si on ne passe aucun argument tout en ayant un certain contrôle en cas de besoin. Si je voulais à ce moment utiliser la fonction en utilisant la valeur de <code>$_GET['search']</code> comme clé de recherche, j&#8217;aurais pu l&#8217;appeler ainsi:</p>
<pre><code>fct_display_news(3, $_GET['search'])</code></pre>
<h3>Troisième péché: la fonction fait trop de choses</h3>
<p>La fonction &laquo;&nbsp;raboute&nbsp;&raquo; des morceaux de requêtes SQL <strong>en créant la fin de la requête</strong> (<code>"WHERE ..."</code>) <strong>en premier</strong>. Je trouve étrange d&#8217;avoir commencé par la fin sans raison apparente. Ça ne fait que complexifier le code.</p>
<p>En plus, pourquoi ne pas avoir simplement séparé la fonction en deux fonctions? Chaque fonction aurait été beaucoup plus claire et facile à maintenir. Exemple:</p>
<pre><code>// mieux
function get_news($quantity = 3, $search = NULL){
    if ($search == NULL)
        return get_latest_news($quantity);
    else // $search != NULL
        return get_searched_news($quantity, $search);
}

function get_lastest_news($quantity = 3){
    // fonction qui retourne les $quantity dernières nouvelles
    // ...
}

function get_searched_news($quantity = 3, $search = NULL){
    // fonction qui retourne les $quantity dernières nouvelles trouvées selon la clé de recherche
    // ...
}</code></pre>
<p>Si on regarde la liste des fonctions du fichier, on se rend vite compte qu&#8217;une approche orienté objet aurait très bien fait la job. Une classe <code>News</code> aurait grandement simplifié le tout.</p>
<h3>Quatrième péché: des noms qui ne veulent rien dire</h3>
<p>Si on retourne dans le code au début de l&#8217;article, on peut voir qu&#8217;il y a plusieurs noms encombrés d&#8217;abréviations superflues ou qui ne veulent rien dire aux yeux de la prochaine personne qui touche le code.</p>
<p>Est-ce que j&#8217;ai vraiment besoin de spécifier dans le nom d&#8217;une fonction qu&#8217;il s&#8217;agit d&#8217;une fonction en y préfixant <code>fct</code>? Aussi, un fichier nommé <code>img_c_btn_savoir_up.gif</code>: un fichier <code>gif</code> est une image, pas besoin de préfixer <code>img</code> à son nom. Dans le même nom de fichier, que veut dire le &laquo;&nbsp;<code>c</code>&laquo;&nbsp;?</p>
<p>Une fonction devrait avoir un nom qui permet de savoir ce qu&#8217;elle fait tout en étant concis. <code>display_news_list</code> aurait été suffisant.</p>
<h3>Cinquième péché: être vulnérable aux injections SQL</h3>
<p>Étant donné que la fonction n&#8217;accepte aucun paramètre, le programmeur a utilisé la valeur de <code>$_GET['search']</code> directement dans sa fonction. Le problème que je veux souligner ici c&#8217;est la manière dont il l&#8217;a utilisée. Il l&#8217;a mis directement dans une requête sans la filtrer:</p>
<pre><code>// mauvais
$query = " WHERE title LIKE CONVERT(_utf8 '%".$_GET['search']."%' USING latin1) OR content LIKE CONVERT(_utf8 '%".$_GET['search']."%' USING latin1)";
</code></pre>
<p>En insérant directement des valeurs fournies par l&#8217;utilisateur (ici, dans la barre d&#8217;adresse) sans les avoir filtrés au préalable est une mauvaise pratique car elle ouvre très grand les portes aux <a href="http://www.hooba.ca/blog/2009/prevenir-les-injections-sql-avec-php-et-mysql/">attaques par injection SQL</a>.</p>
<h3>En conclusion</h3>
<p>Quand on programme, c&#8217;est important de toujours penser à la réutilisabilité du code. Il faut bien sûr parfois faire du code &laquo;&nbsp;<em>quick and dirty</em>&laquo;&nbsp;, mais les choses importantes que je viens d&#8217;énumérer ne sont pas compliqués à respecter. D&#8217;ailleurs, le programmeur aurait en fait sauvé du temps s&#8217;il avait fait du code réutilisable, car il a eu à reprogrammer un autre ensemble complet de fonctions pour le côté administrateur. S&#8217;il avait dès le départ fait une nouvelle classe ou simplement mieux conçu ses fonctions, il aurait facilement pu sauver beaucoup de temps en réutilisant lui-même son propre code à l&#8217;intérieur du même projet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hooba.ca/blog/2009/bon-code-bad-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Prévenir les injections SQL avec PHP et MySQL</title>
		<link>http://www.hooba.ca/blog/2009/prevenir-les-injections-sql-avec-php-et-mysql/</link>
		<comments>http://www.hooba.ca/blog/2009/prevenir-les-injections-sql-avec-php-et-mysql/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 19:12:44 +0000</pubDate>
		<dc:creator>Antoine Leclair</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Sécurité]]></category>

		<guid isPermaLink="false">http://www.hooba.ca/blog/?p=253</guid>
		<description><![CDATA[Tout d&#8217;abord, pour ceux qui ne savent pas ce qu&#8217;est une attaque SQL, je vous fais une brève explication.
Exemple d&#8217;attaque par injection SQL
Une personne mal intentionnée peut tenter d&#8217;abuser votre code PHP en insérant des morceaux de SQL à des endroits que vous vous n&#8217;y attendez pas sur votre site web. Par exemple, une page [...]]]></description>
			<content:encoded><![CDATA[<p>Tout d&#8217;abord, pour ceux qui ne savent pas ce qu&#8217;est une attaque SQL, je vous fais une brève explication.</p>
<h3>Exemple d&#8217;attaque par injection SQL</h3>
<p>Une personne mal intentionnée peut tenter d&#8217;abuser votre code PHP en insérant des morceaux de SQL à des endroits que vous vous n&#8217;y attendez pas sur votre site web. Par exemple, une page qui montre les produits d&#8217;une certaine catégorie à l&#8217;aide d&#8217;un paramètre GET.<span id="more-253"></span> Une version simplifiée de votre code pourrait ressembler à ceci:</p>
<pre><code>&lt;?php
// connection à la base de donnée
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$query = 'SELECT * FROM products WHERE category="'
        .$_GET['category'].'"';
$mysqli->query($query);
// ... suite du code ...
?&gt;</code></pre>
<p>Avec <code>$_GET['category']=&#39;rasoirs&#39;</code>, la requête ressemblerait à ceci:</p>
<pre><code>SELECT * FROM products WHERE category="rasoirs"</code></pre>
<p>Si l&#8217;utilisateur réussi à passer <code>$_GET['category']=&#39;rasoirs&#34; OR 1=1&#39;</code>, la requête se fait transformer en quelque chose du genre:</p>
<pre><code>SELECT * FROM products WHERE category="rasoirs" OR 1=1</code></pre>
<p>L&#8217;exemple ici n&#8217;est pas si dangereux, mais on peut facilement imaginer des requêtes du genre:</p>
<pre><code>UPDATE products SET en_special="1" WHERE category="rasoirs"</code></pre>
<p>devenir des requêtes du genre:</p>
<pre><code>UPDATE products SET en_special="1" WHERE category="rasoirs" OR 1=1</code></pre>
<p>Regardez cet exemple concret d&#8217;<a href="http://xkcd.com/327/">une attaque par injection SQL</a> <img src='http://www.hooba.ca/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<h3>Comment on faisait pour éviter ce problème</h3>
<p>Une pratique encore valide aujourd&#8217;hui est de ne jamais mettre directement des données entrées par un utilisateurs à des endroits qui pourraient affecter de manière nuisible le programme. Dans l&#8217;exemple précédent des catégories, on aurait pu faire quelque chose qui ressemble à:</p>
<pre><code>switch($_GET['category']){
  case 'rasoirs':
    $query = 'SELECT * FROM products WHERE category="rasoirs"';
    break;
// etc.
}</code></pre>
<p>Bien sûr, on doit souvent utiliser les entrées de l&#8217;utilisateurs pour fabriquer des requêtes. Il faut alors filtrer ce que l&#8217;utilisateur envoie, avec des fonctions du genre <code>mysql_real_escape()</code>. Mais cette fonction peut maintenant être compté comme désuette grâce à la compilation des requêtes.</p>
<h3>Nouvelle façon</h3>
<p>Grâce aux nouveaux (okay, pas si nouveau) <em>compiled statements</em> (requêtes compilées), on peut désormais être certain que l&#8217;utilisateur ne réussira pas à déborder hors de ce qu&#8217;on avait prévu initiallement. Voici un exemple:</p>
<pre><code>$query = 'INSERT INTO users (name, password, date_added) '
        .'VALUES (?, ?, ?);
$stmt = $mysqli->prepare($query);
if ($stmt){
  $stmt->bind_param('ssi', $name, $password, $date_added);
  // s pour string, i pour integer
  $stmt->execute();
}
</code></pre>
<p>La requête SQL est donc compilée avant même de savoir ce qui se tiendra à la place des <code>?</code>. On ne fait qu&#8217;assigner plus tard ce qui les remplacera.</p>
<p>Premier avantage, qui est le sujet de mon article, est que ça prévient les attaques SQL. Dans l&#8217;exemple des catégories de produits ci-haut, même si l&#8217;utilisateur réussissait à assigner une valeur du genre <code>rasoirs" OR 1=1</code> à notre variable qui ira dans notre requête SQL, la requête était déjà compilée. La requête aura donc l&#8217;effet de celle-ci:</p>
<pre><code>SELECT * FROM products WHERE category="rasoirs\" OR 1=1"</code></pre>
<p>Elle cherchera donc RÉELLEMENT les produits appartenant à la catégorie <code>rasoirs" OR 1=1</code> (qui n&#8217;existe pas).</p>
<p>Deuxième avantage des requêtes précompilées, c&#8217;est que si vous avez à exécuter plusieurs requetes dont seulement certain paramètres changent, en ne compilant qu&#8217;une seule fois la requête et en l&#8217;exécutant avec différentes variables, vous sauver du temps-machine. Lorsque vous y allez &laquo;&nbsp;à l&#8217;ancienne&nbsp;&raquo;, le requête est compilée à chaque fois.</p>
<h3>Conclusion et liens</h3>
<p>La plupart des bases de données offrent aujourd&#8217;hui la possibilité de compiler ses requête à l&#8217;avance et je trouve que c&#8217;est une excellente pratique de profiter de cette fonctionnalité.</p>
<p>Les PDO (PHP Data Objects) n&#8217;offrent qu&#8217;une abstraction très mince au-dessus des bases de données. Ils n&#8217;offrent générallement pas de fonctionnalités ajoutées. Pourtant, les concepteurs ont décidé d&#8217;implémenter dans les PDO la possibilité de compiler ses requêtes même lorsque la base de donnée utilisée ne l&#8217;accepte pas! Ils s&#8217;en chargent pour nous. Pour vous dire à quel point c&#8217;est important.</p>
<p>Si vous voulez un peu plus d&#8217;information sur les attaques SQL, vous pouvez lire cette <a href="http://en.wikipedia.org/wiki/SQL_injection">page de Wikipedia</a> et cette <a href="http://www.unixwiz.net/techtips/sql-injection.html">page web</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hooba.ca/blog/2009/prevenir-les-injections-sql-avec-php-et-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
