<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>php-experts.org - développement php et internet</title>
	
	<link>http://www.php-experts.org</link>
	<description>Ressources sur le développement internet, PHP/MySQL, Ajax, marketing online, référencement...</description>
	<lastBuildDate>Wed, 17 Jun 2009 03:50:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/php-experts-org-developpement-php-internet" type="application/rss+xml" /><item>
		<title>Symfony Live, par Sensio Labs</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/-DPXg7lFyEs/symfony-live-par-sensio-labs-290</link>
		<comments>http://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290#comments</comments>
		<pubDate>Mon, 08 Jun 2009 23:18:25 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[Actualités PHP]]></category>
		<category><![CDATA[afup]]></category>
		<category><![CDATA[conférence]]></category>
		<category><![CDATA[sensio labs]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=290</guid>
		<description><![CDATA[Sensio Labs organise la 1ère édition du Symfony Live, conférence francophone dédiée au framework PHP open source Symfony. ( Rendez-vous les 11 &#038; 12 juin, Cité Universitaire Internationale Paris 14° ).
Au programme de ces deux journées :
- Conférences inédites sur les thèmes : réseaux sociaux, stratégies de migration, gestion de médias, Symfony 2…
- Retours d’expériences [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sensiolabs.com/fr">Sensio Labs</a> organise la 1ère édition du Symfony Live, conférence francophone dédiée au framework PHP open source Symfony. ( Rendez-vous les 11 &#038; 12 juin, Cité Universitaire Internationale Paris 14° ).</p>
<p>Au programme de ces deux journées :<br />
- Conférences inédites sur les thèmes : réseaux sociaux, stratégies de migration, gestion de médias, Symfony 2…<br />
- Retours d’expériences : Dailymotion, Yahoo!, L’Express…<br />
- Experts : Fabien Potencier, Créateur et Lead developer de Symfony et PDG de Sensio Labs, Dustin Whittle, évangéliste Yahoo!, Jonathan Wage, Lead developer de Doctrine ORM…</p>
<p>Programme complet ici : <a href="http://www.symfony-live.com/schedule">http://www.symfony-live.com/schedule</a></p>
<p>A noter, cette manifestation a aussi le soutien de la très sérieuse <a href="http://afup.org/">AFUP</a>. Cette première conférence française entièrement consacrée au framework Symfony est très attendue dans la communauté et personnellement, si mon agenda l&#8217;avait permis, j&#8217;aurais beaucoup aimé pouvoir y montrer mon nez.<br />
Vous pourrez suivre la conférence en direct sur Twitter (<a rel="nofollow" href="http://twitter.com/sflive09fr">@sflive09fr</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/php-developpement-web/actualites-php/symfony-live-par-sensio-labs-290</feedburner:origLink></item>
		<item>
		<title>Procédures et fonctions sous MySQL: les bases</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/2kxMOfakUTI/procedures-et-fonctions-sous-mysql-les-bases-231</link>
		<comments>http://www.php-experts.org/bases-de-donnees/mysql/procedures-et-fonctions-sous-mysql-les-bases-231#comments</comments>
		<pubDate>Sun, 10 May 2009 21:37:21 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=231</guid>
		<description><![CDATA[Oracle dispose d&#8217;un langage appelé PL/SQL pour compiler des procédures et des fonctions sur le serveur. Ces procédures et fonctions peuvent être appelées directement en SQL. Quand elles sont écrites correctement, elles permettent en général un gain de performances non négligeable, en plus d&#8217;être pratiques et agréables à utiliser. En gros, les procédures et fonctions [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Oracle</strong> dispose d&#8217;un langage appelé <strong>PL/SQL</strong> pour compiler des <strong>procédures et des fonctions</strong> sur le serveur. Ces procédures et fonctions peuvent être appelées directement en SQL. Quand elles sont écrites correctement, elles permettent en général un <strong>gain de performances non négligeable</strong>, en plus d&#8217;être pratiques et agréables à utiliser. En gros, les procédures et fonctions sont un excellent moyen d&#8217;apporter une couche d&#8217;intelligence supplémentaire à votre serveur de bases de données, en lui permettant d&#8217;exécuter des actions complexes sans avoir recours à des scripts extérieurs. On économise donc le protocole de communication entre base de données et application. Et bien&#8230; C&#8217;est possible aussi sous MySQL !<br />
<span id="more-231"></span></p>
<h2>Mini rappel : Procédure, ou fonction ?</h2>
<p>Si vous hésitez entre créer une procédure stockée ou une fonction, rappelez vous bien que la seule différence entre les deux est qu&#8217;une fonction va chercher un résultat (quitte à passer par des tonnes d&#8217;étapes intermédiaires), alors qu&#8217;une procédure va faire une action. En gros, si vous voulez avoir une valeur de retour, il vous faut une fonction. Dans le cas contraire, préférez une procédure.</p>
<h2>Dans quel cas les utiliser, et comment ?</h2>
<p>Vous pouvez vous tourner vers les <strong>ProcStock</strong> (pour &#8220;procédures stockées&#8221;, le terme étant souvent utilisé aussi pour les fonctions) partout où vous exécutez des traitements de calculs lourds et/ou sur de gros volumes de données. L&#8217;avantage énorme est que vous n&#8217;aurez pas à rapatrier des resultsets de grande taille, pour les traiter en PHP (par exemple), puis les insérer en base: tout se fera directement en une seule requête très simple, qui appellera la fonction/procédure.<br />
Les fonctions MySQL que vous allez définir s&#8217;utilisent exactement comme les fonctions prédéfinies (bien que celles-ci soient en général écrites en C et compilées avec le serveur&#8230; c&#8217;est faisable aussi pour un gain maximal en performances MySQL, mais ceci est une autre histoire), comme par exemple AVG (qui calcule une moyenne sur les valeurs d&#8217;un champ). Sans AVG (syntaxe: SELECT AVG(champ) FROM table), il faudrait récupérer les résultats concernés, les ajouter, puis les diviser par leur nombre : (1+5+6)/3 = 4. AVG fait ça toute seule et renvoie directement 4. Bien évidemment, il n&#8217;est pas bien grave d&#8217;avoir à récupérer 3 lignes. Mais avec 20.000 enregistrements, c&#8217;est différent, et les performances seront affectées, notamment en raison de l&#8217;utilisation de RAM nécessaire à l&#8217;exécution du script.<br />
Il peut être aussi très intéressant d&#8217;utiliser des procédures et fonctions sur le serveur de bases de données quand plusieurs applications frontend dans des langages différents peuvent avoir à réaliser les mêmes actions: plutôt que d&#8217;écrire (et maintenir&#8230;) les actions communes en plusieurs langages, autant déporter leur exécution sur le serveur SQL, et demander aux clients de seulement interagir avec les fonctions stockées.</p>
<h3>Application concrète</h3>
<p><em>(je déplore mon manque d&#8217;imagination, qui m&#8217;oblige à chaque post à sortir des exemples totalement improbables&#8230;)</em><br />
Imaginons un site de vente en ligne. Chaque jour est généré un rapport, enregistré en base, qui, en fonction du détail des ventes de la journée, calcule des indicateurs comme le chiffre d&#8217;affaires global et le panier moyen.<br />
On aurait donc une table &#8220;commandes&#8221; avec un champ &#8220;montant&#8221; et un champ &#8220;date&#8221; (je simplifie, hein).<br />
En PHP, sans procstock, il faut :</p>
<ul>
<li>Envoyer une requête qui prend les ventes de la journée passée</li>
<li>Récupérer dans un tableau le détail des transactions</li>
<li>Faire les calculs nécessaires (nombre de lignes, moyenne des montants, total des montants)</li>
<li>Stocker ces résultats en base</li>
</ul>
<p>Au bas mot, cela représente une vingtaine de lignes de PHP, avec deux communications depuis/vers la base de données, une boucle qui parse le tableau, des variables temporaires&#8230;<br />
Dans cette situation, c&#8217;est d&#8217;une <strong>procédure</strong> stockée que nous avons besoin. On ne récupère pas les infos (pas de valeur retournée) mais on les stocke en base. Dans le cas contraire, on aurait créé une <strong>fonction</strong>.<br />
La procédure stockée en question, que nous appellerons &#8220;genere_rapport&#8221;, va s&#8217;occuper de tout cela pour nous. Voici son code :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">DELIMITER //;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">CREATE</span> PROCEDURE genere_rapport<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; BEGIN</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; DECLARE nb_commandes INTEGER<span class="br0">&#40;</span><span class="nu0">5</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; DECLARE panier,chiffre_affaires FLOAT;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">SELECT</span> COUNT<span class="br0">&#40;</span>*<span class="br0">&#41;</span>,AVG<span class="br0">&#40;</span>montant<span class="br0">&#41;</span>,SUM<span class="br0">&#40;</span>montant<span class="br0">&#41;</span> <span class="kw1">INTO</span> nb_commandes,panier,chiffre_affaires <span class="kw1">FROM</span> commandes <span class="kw1">LIMIT</span> <span class="nu0">1</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">INSERT</span> <span class="kw1">INTO</span> rapports <span class="br0">&#40;</span>nb_com, panier_moyen, ca_total<span class="br0">&#41;</span> <span class="kw1">VALUES</span> <span class="br0">&#40;</span>nb_commandes, panier, chiffre_affaires<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; END//</div>
</li>
<li class="li1">
<div class="de1">DELIMITER ;</div>
</li>
</ol>
</div>
<p>MySQL devrait répondre &#8220;Query OK, 0 rows affected (0.01 sec)&#8221; pour signaler que la procstock a bien été créée.<br />
Première remarque, on change le délimiteur de fin de commande MySQL. La création d&#8217;une procédure/fonction doit se faire en une seule instruction MySQL, même si la procstock comporte plusieurs instructions à exécuter. J&#8217;avoue que ça surprend au début mais c&#8217;est un coup à prendre. Pensez bien à remettre le délimiteur normal (le point-virgule) après la création de votre procstock.<br />
Ensuite, on lance la création de la procédure. On déclare d&#8217;abord les variables dont on aura besoin pour stocker les données (même si ici, on aurait pu directement faire le SELECT dans une sous-requête de l&#8217;INSERT, mais ce n&#8217;est pas le but): la liste des types disponibles est la même que les types des champs. On utilise ensuite SELECT INTO avec le nom de nos variables pour dire à MySQL dans quelle variable stocker quelle valeur, variables qu&#8217;on utilise ensuite dans une requête INSERT classique pour stocker le rapport.<br />
Pour appeler la procédure, on fera CALL genere_rapport();. Pour une fonction, ça sera SELECT nom_de_la_fonction();</p>
<h2>Conclusion</h2>
<p>Penchez-vous sur vos applications PHP, il y a certainement des tas d&#8217;actions que vous pourrez déporter vers des procédures stockées. Les gains de performances devraient être rapidement ressentis, pour un effort d&#8217;apprentissage minimal.<br />
Dans un prochain post, nous irons plus loin avec les procédures stockées, en utilisant notamment des paramètres, des curseurs, des handlers, et autres joyeusetés. Le plus difficile sera de trouver un exemple intéressant&#8230; <img src='http://www.php-experts.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/bases-de-donnees/mysql/procedures-et-fonctions-sous-mysql-les-bases-231/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/bases-de-donnees/mysql/procedures-et-fonctions-sous-mysql-les-bases-231</feedburner:origLink></item>
		<item>
		<title>CSV et MySQL : SELECT INTO OUTFILE et LOAD DATA INFILE</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/PyqArwTSkfA/csv-mysql-select-into-outfile-load-data-infile-206</link>
		<comments>http://www.php-experts.org/bases-de-donnees/mysql/csv-mysql-select-into-outfile-load-data-infile-206#comments</comments>
		<pubDate>Mon, 27 Apr 2009 01:05:07 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[csv]]></category>
		<category><![CDATA[export]]></category>
		<category><![CDATA[import]]></category>
		<category><![CDATA[LOAD DATA INFILE]]></category>
		<category><![CDATA[SELECT INTO OUTFILE]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=206</guid>
		<description><![CDATA[J&#8217;ai eu à me pencher sur les imports-exports sous MySQL. Mon but était de disposer de fichiers utilisables dans un format &#8220;humain&#8221; (comprendre: que les gens du marketing pouvaient exploiter avec leur cher Excel) sans pour autant passer par des scripts de conversion hasardeux et lourds pour le serveur. Il a donc fallu que je [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai eu à me pencher sur les <strong>imports-exports sous MySQL</strong>. Mon but était de disposer de fichiers utilisables dans un format &#8220;humain&#8221; (comprendre: que les gens du marketing pouvaient exploiter avec leur cher Excel) sans pour autant passer par des scripts de conversion hasardeux et lourds pour le serveur. Il a donc fallu que je cherche les meilleures solutions pour pouvoir générer et importer des <strong>fichiers CSV dans MySQL</strong>,mon SGBDR favori. J&#8217;ai dû me servir du couple SELECT INTO OUTFILE pour les exports, et LOAD DATA INFILE pour les imports. Petit rappel syntaxique.<br />
<span id="more-206"></span></p>
<h2>Exports CSV avec MySQL : SELECT INTO OUTFILE</h2>
<p>Le principe de <strong>SELECT INTO OUTFILE</strong> est simple: réaliser un export de données en écrivant un resultset (résultats d&#8217;exécution d&#8217;une requête) directement dans un fichier CSV sur le serveur. Pour cela, l&#8217;utilisateur avec lequel vous vous connectez à MySQL doit avoir le priilège &#8220;FILE&#8221;. Autre remarque, vous ne pourrez en aucun cas écraser un fichier déjà existant sur le serveur (ceci pour la simple et bonne raison qu&#8217;il serait assez dommageable d&#8217;écraser, par exemple, votre fichier /etc/passwd).</p>
<p>Voici donc la syntaxe, finalement assez simple, de la fonction SELECT INTO OUTFILE :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> champ</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">FROM</span> <span class="kw1">TABLE</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">WHERE</span> champ = <span class="st0">&#8216;valeur cherchée&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">INTO</span> <span class="kw1">OUTFILE</span> <span class="st0">&#8216;/var/dump.csv&#8217;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">FIELDS</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; TERMINATED <span class="kw1">BY</span> <span class="st0">&#8216;;&#8217;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">OPTIONALLY</span> <span class="kw1">ENCLOSED</span> <span class="kw1">BY</span> <span class="st0">&#8216;&quot;&#8217;</span></div>
</li>
</ol>
</div>
<p>Dans le fichier exporté, les champs ne sont pas délimités, sauf si vous utilisez FIELDS ENCLOSED BY. Le OPTIONALLY spécifie que seules les chaînes de caractères doivent être encadrées.<br />
Le délimiteur par défaut est l&#8217;espace. Pour en utiliser un autre (virgule, point-virgule, tabulation, &#8230;) il faut utiliser la directive FIELDS TERMINATED BY. Evidemment, on peut utiliser des caractères spéciaux comme la tabulation &#8216;t&#8217; ou le retour à la ligne &#8216;n&#8217; (éventuellement CR+LF sous Windows, donc &#8216;rn&#8217;). Il existe aussi LINES TERMINATED BY pour contrôler le caractère de fin de ligne.</p>
<p>Du coup, en lançant sur la base de mon blog cette requête :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">mysql&gt; <span class="kw1">SELECT</span> ID,post_title,comment_count</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">FROM</span> <span class="st0">`wp_posts`</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">WHERE</span> <span class="st0">`post_status`</span> = <span class="st0">&#8216;publish&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"> <span class="kw1">ORDER</span> <span class="kw1">BY</span> <span class="st0">`post_date`</span> <span class="kw1">DESC</span> <span class="kw1">LIMIT</span> <span class="nu0">3</span></div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">INTO</span> <span class="kw1">OUTFILE</span> <span class="st0">&#8216;/tmp/blog_posts.dump&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">FIELDS</span></div>
</li>
<li class="li1">
<div class="de1">TERMINATED <span class="kw1">BY</span> <span class="st0">&#8216;;&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">OPTIONALLY</span> <span class="kw1">ENCLOSED</span> <span class="kw1">BY</span> <span class="st0">&#8216;&quot;&#8217;</span>;</div>
</li>
</ol>
</div>
<p>j&#8217;ai pu récupérer un fichier plat qui donnait :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">179;&quot;plugin : yURL ReTwitt&quot;;1
</div>
</li>
<li class="li1">
<div class="de1">22;&quot;5 plugins indispensables pour coder en PHP avec l&#8217;IDE Eclipse&quot;;0
</div>
</li>
<li class="li1">
<div class="de1">138;&quot;plugin : wp_list_sub_pages()&quot;;0</div>
</li>
</ol>
</div>
<p>Soit, un joli fichier CSV bien propre, directement exploitable (pourquoi pas par Excel).</p>
<h2>Imports de CSV dans MySQL : LOAD DATA INFILE</h2>
<p>Le LOAD DATA INFILE, qui permet de faire l&#8217;exact inverse du INTO OUTFILE, est tout aussi simple à utiliser. Dans les bonnes conditions, c&#8217;est vraiment l&#8217;un des outils d&#8217;<strong>import MySQL</strong> les plus puissants.<br />
Déjà, bonne nouvelle, la syntaxe des commandes qui permet à LOAD DATA INFILE de repérer les débuts et fin de champs (et de ligne) est la même que pour SELECT INTO OUTFILE. On retrouve donc sans surprise les FIELDS TERMINATED BY et autres joyeusetés.<br />
Une gestion des doublons est aussi possible grâce aux mots-clefs IGNORE et REPLACE, qui parlent d&#8217;eux-même. Déclenchés en cas de doublon dans une clé (primaire ou unique), REPLACE effacera l&#8217;ancienne ligne pour la remplacer par la nouvelle. Attention donc, vous perdrez donc la pérennité de vos ID puisque ceux-ci changeront lors de l&#8217;import de données. IGNORE permettra simplement de conserver l&#8217;ancienne ligne, les nouvelles données n&#8217;étant pas écrites: vous conservez vos ID mais perdez le bénéfice de l&#8217;import sur cette ligne.<br />
Vous pouvez aussi spécifier la liste des champs dans lesquelles les données doivent être stockées avec la syntaxe classique &#8220;(champ1, champ2, champ3)&#8221; (sans guillemets) en fin de commande.<br />
Pour prendre un exemple, avec un fichier de la forme :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">1;120;&quot;texte1&quot;;
</div>
</li>
<li class="li1">
<div class="de1">2;240;&quot;texte2&quot;;</div>
</li>
</ol>
</div>
<p>En imaginant qu&#8217;on ne veut garder que l&#8217;id (champ 1) et le texte (champ 3), et les insérer dans les champs correspondants de la table SQL &#8220;data&#8221;, on peut utiliser le paramètre @dummy pour demander au serveur d&#8217;ignorer l&#8217;un des champs du CSV. Cela nous donne une requête de la forme :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">LOAD</span> <span class="kw1">DATA</span> <span class="kw1">INFILE</span> <span class="st0">&#8216;/tmp/data.csv&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">INTO</span> <span class="kw1">TABLE</span> <span class="st0">`data`</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">FIELDS</span></div>
</li>
<li class="li1">
<div class="de1">TERMINATED <span class="kw1">BY</span> <span class="st0">&#8216;;&#8217;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">OPTIONALLY</span> <span class="kw1">ENCLOSED</span> <span class="kw1">BY</span> <span class="st0">&#8216;&quot;&#8217;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#40;</span>id, @dummy, texte<span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Et si par malheur votre fichier commence par 2 lignes d&#8217;entête, pas de souci, vous pouvez présicer IGNORE 2 LINES dans la requête pour que soient ignorées les 2 premières lignes.</p>
<p>Et voila. Deux commandes, finalement pas bien complexes une fois qu&#8217;on les a prises en main, qui permettent de gérer efficacement les imports/exports de fichiers CSV sous MySQL. Pour faire suite à cet article, nous verrons bientôt comment optimiser la vitesse de vos INSERT dans MySQL.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/bases-de-donnees/mysql/csv-mysql-select-into-outfile-load-data-infile-206/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/bases-de-donnees/mysql/csv-mysql-select-into-outfile-load-data-infile-206</feedburner:origLink></item>
		<item>
		<title>5 plugins indispensables pour coder en PHP avec l’IDE Eclipse</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/M5gGyyIYt-I/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22</link>
		<comments>http://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22#comments</comments>
		<pubDate>Mon, 13 Apr 2009 11:55:21 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[Développement Web]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=22</guid>
		<description><![CDATA[L&#8217;IDE Eclipse, conçu à l&#8217;origine pour développer en Java, s&#8217;est enrichi de fonctionnalités avancées, sous forme de plugins, qui lui permettent aujourd&#8217;hui de jouer dans la cours des grands des éditeurs de code PHP. Tour d&#8217;horizon de ceux que j&#8217;utilise.
1. Eclipse PDT
Vu ses parents, Zend et IBM, le projet Eclipse PDT est un &#8220;(Php) Development [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-32" style="float:left;padding-right:10px" title="Eclipse" src="http://www.php-experts.org/wp-content/uploads/2008/11/eclipse.png" alt="" width="200" height="101" />L&#8217;IDE <strong>Eclipse</strong>, conçu à l&#8217;origine pour développer en Java, s&#8217;est enrichi de fonctionnalités avancées, sous forme de plugins, qui lui permettent aujourd&#8217;hui de jouer dans la cours des grands des <strong>éditeurs de code PHP</strong>. Tour d&#8217;horizon de ceux que j&#8217;utilise.<span id="more-22"></span></p>
<h2 style="padding-top:30px">1. Eclipse PDT</h2>
<p>Vu ses parents, Zend et IBM, le projet Eclipse PDT est un &#8220;(Php) Development Tools framework&#8221; complet. Il étend les capacités natives de la plate-forme Eclipse pour permettre de développer calmement des applications solides en PHP. Pas vraiment besoin de le présenter, si ?<br />
Eclipse PDT est téléchargeable en tant que plug-in ou en version &#8220;bundle&#8221; (PDT all-in-one), c&#8217;est à dire avec Eclipse et tous les composants de base. Ceci est très utile dans le cas d&#8217;une nouvelle installation.<br />
<a rel="nofollow" href="http://www.eclipse.org/pdt/downloads/">Télécharger Eclipse PDT</a></p>
<p>Il existe d&#8217;autres plugins permettant d&#8217;ajouter à Eclipse le support du PHP, comme <a rel="nofollow" href="http://www.phpeclipse.de/">PHPEclipse</a> ou <a rel="nofollow" href="http://www.eclipse.org/php/">Eclipse PHP IDE</a>, développé par Zend.</p>
<h2 style="padding-top:30px">2. RegEx Util</h2>
<p>Editeur d&#8217;expressions régulières, toujours pratique de part le fait qu&#8217;il surligne les expressions qui matchent quand on sélectionne une partie du pattern. Il permet aussi de rationaliser ses expressions, notamment en utilisant les classes prédéfinies -comme [alphanum]</p>
<p>Site officiel : <a rel="nofollow" href="http://myregexp.com/eclipsePlugin.html">http://myregexp.com/eclipsePlugin.html</a><br />
Update Site : <a rel="nofollow" href="http://regex-util.sourceforge.net/update/">http://regex-util.sourceforge.net/update/</a></p>
<div id="attachment_28" class="wp-caption aligncenter" style="width: 500px"><img class="size-full wp-image-28" title="RegexUtil" src="http://www.php-experts.org/wp-content/uploads/2008/11/regexutil.jpg" alt="RegexUtil pour Eclipse" width="490" height="116" /><p class="wp-caption-text">RegexUtil pour Eclipse</p></div>
<h2 style="padding-top:30px">3. SubClipse</h2>
<div id="attachment_30" class="wp-caption alignright" style="width: 310px"><img class="size-medium wp-image-30" title="SubClipse" src="http://www.php-experts.org/wp-content/uploads/2008/11/subclipse-300x138.jpg" alt="SVN pour Eclipse avec Subclipse" width="300" height="138" /><p class="wp-caption-text">SVN pour Eclipse avec Subclipse</p></div>
<p>Ajoute le support de SVN (SubVersion) à Eclipse. SVN est un système de gestion de versionning comme CVS intégrant quelques améliorations, comme la possibilité de déplacer et supprimer des fichiers, sans perdre leur historique.</p>
<p>Site officiel : <a rel="nofollow" href="http://subclipse.tigris.org/">http://subclipse.tigris.org/</a><br />
Update Site (pour la branche 1.6) : <a rel="nofollow" href="http://subclipse.tigris.org/update_1.6.x">http://subclipse.tigris.org/update_1.6.x</a></p>
<h2 style="padding-top:30px">4. Remote System Explorer (RSE)</h2>
<p>Permet notamment d&#8217;éditer ses fichiers directement via une connexion SSH. Je m&#8217;en sers pour les petites retouches de code PHP rapides qui ne peuvent &#8220;pas attendre&#8221;.</p>
<p>Site officiel : <a href="http://www.eclipse.org/dsdp/tm/tutorial/">http://www.eclipse.org/dsdp/tm/tutorial/</a><br />
Update Site : <a rel="nofollow" href="http://download.eclipse.org/dsdp/tm/updates">http://download.eclipse.org/dsdp/tm/updates</a></p>
<h2 style="padding-top:30px">5. Azzuri Clay</h2>
<div id="attachment_148" class="wp-caption alignleft" style="width: 243px"><img class="size-medium wp-image-148" title="azzurri clay" src="http://www.php-experts.org/wp-content/uploads/2009/04/bdd097.png" alt="azzurri clay" width="233" height="208" /><p class="wp-caption-text">Azzurri Clay: bases de données sous Eclipse</p></div>
<p>Un peu difficile à prendre en mains, <strong>Azzuri Clay</strong> est un plugin commercial pour Eclipse qui permet d&#8217;ajouter un vrai support des bases de donnéees. Le système de licence adopté est un peu étrange: la version Pro ne peut être achetée qu&#8217;au Japon. Il n&#8217;en reste pas moins que l&#8217;édition classique, gratuite, est toujours intéressante.<br />
La liste des SGBDR supportés est assez impressionnante vu qu&#8217;elle comprend, notamment, les classiques MySQL, PostGres, Oracle, MS SQL Server, DB2, Informix, mais aussi, beaucoup plus rare, SAP.</p>
<p>Pour se servir du Database Modeler d&#8217;Azzuri Clay, il faut créer un projet (ou utiliser un projet déjà existant) et faire File -&gt; New -&gt; Other -&gt; Database Modeling -&gt; Azzurri Clay Database Design Diagram.</p>
<p>Une fois cela fait, on peut créer ses premières tables, exporter les scripts SQL de création (selon le SGBDR choisi), et même faire du retro engineering sur des bases de données déjà crées.</p>
<p>Site officiel : <a rel="nofollow" href="http://www.azzurri.jp/en/clay/index.html">http://www.azzurri.jp/en/clay/index.html</a><br />
Update Site : <a rel="nofollow" href="http://www.azzurri.co.jp/eclipse/plugins">http://www.azzurri.co.jp/eclipse/plugins</a></p>
<h3 style="padding-top:30px">Références pour Eclipse</h3>
<p><a href="http://www.thierryb.net/site/Installation-minimale-d-Eclipse.html">Installation minimale d&#8217;Eclipse</a>, par Thierry Bothorel</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/5-plugins-indispensables-pour-coder-en-php-avec-lide-eclipse-22</feedburner:origLink></item>
		<item>
		<title>Moteur de template : Smarty</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/-HpW4ji1Yuw/moteur-de-template-smarty-80</link>
		<comments>http://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80#comments</comments>
		<pubDate>Sun, 08 Mar 2009 22:38:15 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[classes]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[objet]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=80</guid>
		<description><![CDATA[Smarty est un moteur de template. Basiquement, l&#8217;utilité d&#8217;un moteur de templates est de séparer le code métier de l&#8217;affichage que génèrera votre application web. Smarty se présente sous la forme d&#8217;une classe qui gère un langage de balises permettant d&#8217;afficher dynamiquement du code. Ces templates sont compilés et mis en cache (les versions compilées [...]]]></description>
			<content:encoded><![CDATA[<p>Smarty est un moteur de template. Basiquement, l&#8217;utilité d&#8217;un moteur de templates est de séparer le code métier de l&#8217;affichage que génèrera votre application web. Smarty se présente sous la forme d&#8217;une classe qui gère un langage de balises permettant d&#8217;afficher dynamiquement du code. Ces <strong>templates</strong> sont compilés et mis en cache (les versions compilées étant en php, elles profitent d&#8217;éventuels accélérateurs comme <a title="Alternative PHP Cache" href="http://www.php-experts.org/developpement-web/php-developpement-web-2/cache-dopcode-alternative-php-cache-apc-62">APC</a>). Le moteur de template Smarty est si riche de fonctionnalités que je lui consacrerai une série d&#8217;articles. Pour commencer, nous verrons l&#8217;utilisation basique de Smarty, l&#8217;utilisation du <a href="http://www.php-experts.org/developpement-web/php-developpement-web-2/moteur-de-template-smarty-80#literal">tag {literal}</a> ainsi que la <a href="http://www.php-experts.org/developpement-web/php-developpement-web-2/moteur-de-template-smarty-80#dates">gestion des dates</a>.<br />
<span id="more-80"></span></p>
<h2>Principe de fonctionnement</h2>
<p>Admettons que sur votre nouveau site social-2.0-multimedia (etc), vous avez une fiche utilisateur. Chaque fiche comportera, peu ou prou, les mêmes informations, notamment le login de l&#8217;utilisateur. Voici comment procéder. Créez d&#8217;abord un fichier user.tpl (Note sur les fichiers .tpl : l&#8217;extension est libre, mais l&#8217;usage du .tpl est une convention; la plupart des IDE possédent des plug-ins pour permettre l&#8217;analyse et la coloration syntaxique de ce language de balises. Pour les puristes -je ne parle pas pour moi-, on peut justifier l&#8217;emploi du &#8220;tpl&#8221; au lieu d&#8217;un &#8220;html&#8221; plus classique par le fait que les templates contiendront certes du HTML, mais aussi des instructions destinées au moteur de template&#8230; mais bref!) . Ce fichier contiendra :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">Login : &lt;strong&gt;{$login}&lt;/strong&gt;</div>
</li>
</ol>
</div>
<p>Le fichier php qui l&#8217;utilisera contiendra, lui :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$smarty</span> = <span class="kw2">new</span> Smarty<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$smarty</span>-&gt;<span class="me1">assign</span><span class="br0">&#40;</span><span class="st0">&#8216;login&#8217;</span>,<span class="re0">$user_login</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$smarty</span>-&gt;<span class="me1">display</span><span class="br0">&#40;</span><span class="st0">&#8216;user.tpl&#8217;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>On instancie un objet de la classe Smarty (ligne 1) on déclare une <strong>variable de template</strong> appelée &#8216;login&#8217; qui contiendra la valeur de la variable php $user_login (ligne 2). On demande ensuite à Smarty d&#8217; &#8220;exécuter&#8221; et d&#8217;afficher le fichier user.tpl (ligne 3).<br />
Vous l&#8217;aurez compris, le login de l&#8217;utilisateur apparaîtra en lieu et place du {$login} dans le fichier template. Les {} indiquent à Smarty que ce code doit être exécuté, et non directement reproduit en sortie (ce qui est le cas du HTML). Ces signes encadreront toutes les balises Smarty. Vous remarquerez que la variable se déclare en php sans le signe $, mais qu&#8217;il faut utiliser celui-ci lorsqu&#8217;on veut accéder à la valeur de la variable dans le fichier de template.</p>
<h2>Gestion des tableaux sous Smarty</h2>
<p>Si, en PHP, on assigne une tableau à une variable Smarty, on peut y accéder grâce au point, avec la syntaxe <strong>$tableau.index</strong>.</p>
<h2>Fonctions prédéfinies</h2>
<p>(lien vers la doc officielle)</p>
<h2>Le tag {literal}<a name="literal"></a></h2>
<p>S&#8217;il vous arrive de devoir utiliser des accolades {} dans le code&#8211;source de votre template (par exemple pour y intégrer des fonctions JavaScript), il faut les entourer du tag Smarty {literal}{/literal}, afin d&#8217;indiquer au moteur de template de ne pas parser le contenu, ce qui provoquerait une erreur.</p>
<h2>Gestion des dates avec Smarty<a name="dates"></a></h2>
<p>Smarty gère l&#8217;affichage des dates très efficacement grâce à un modificateur de variable (un filtre) nommé date_format. La <strong>syntaxe de date_format sous Smarty</strong> est la suivante :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><a href="http://www.php.net/date"><span class="kw3">Date</span></a> : <span class="br0">&#123;</span><span class="re0">$date_user</span>|date_format:<span class="st0">&quot;%A %d %B %Y à %Hh%M&quot;</span><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Qui affiche :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">Date : Sunday 15 February 2009 à 13h59</div>
</li>
</ol>
</div>
<p>Pour passer la date que Smarty va afficher en français, il suffit d&#8217;utiliser setlocale() en php, comme ceci:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><a href="http://www.php.net/setlocale"><span class="kw3">setlocale</span></a><span class="br0">&#40;</span>LC_ALL, <span class="st0">&#8216;fr_FR&#8217;</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>(n&#8217;hésitez pas à me dire si vous voulez un post plus complet sur l&#8217;installation &#8211; au moins sous Debian &#8211; et l&#8217;utilisation des locales en php). La date affichée devient alors :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">Date : Dimanche 15 février 2009 à 13h59</div>
</li>
</ol>
</div>
<p>Voici les options que vous pouvez passer à la <strong>fonction date_format</strong> de smarty :</p>
<ul>
<li> %a &#8211; Abréviation du jour de la semaine, selon les paramètres locaux.</li>
<li> %A &#8211; Nom du jour de la semaine, selon les paramètres locaux.</li>
<li> %b &#8211; Abréviation du nom du jour, selon les paramètres locaux.</li>
<li> %B &#8211; Nom complet du mois, selon les paramètres locaux.%c &#8211; Préférences d&#8217;affichage selon les paramètres locaux.</li>
<li> %C &#8211; Siècle, (L&#8217;année divisée par 100 et tronquée comme un entier, de 00 à 99)</li>
<li> %d &#8211; Jour du mois, en tant que nombre décimal (de 01 à 31)</li>
<li> %D &#8211; même chose que %m/%d/%y</li>
<li> %e &#8211; Jour du mois en tant que nombre décimal. Un chiffre unique est précédé par un espace (de 1 à 31)</li>
<li> %g &#8211; Position de la semaine dans le siècle [00,99]</li>
<li> %G &#8211; Position de la semaine, incluant le siècle [0000,9999]</li>
<li> %h &#8211; identique à %b</li>
<li> %H &#8211; L&#8217;heure en tant que décimale, en utilisant une horloge sur 24 (de 00 à 23)</li>
<li> %I &#8211; L&#8217;heure en tant que décimale en utilisant une horloge sur 12 (de 01 to 12)</li>
<li> %j &#8211; jour de l&#8217;année (de 001 à 366)</li>
<li> %k &#8211; Heure (horloge sur 24). Les numéros à un chiffre sont précédés d&#8217;un espace. (de 0 à 23)</li>
<li> %l &#8211; Heure (horloge sur 12). Les numéros à un chiffre sont précédés d&#8217;un espace. (de 1 à 12)</li>
<li> %m &#8211; Mois en tant que nombre décimal (de 01 à 12)</li>
<li> %M &#8211; Minute en tant que nombre décimal</li>
<li> %n &#8211; Retour chariot (nouvelle ligne).</li>
<li> %p &#8211; soit am soit pm selon l&#8217;heure donnée, ou alors leurs correspondances locales.</li>
<li> %r &#8211; heure en notation a.m. et p.m.</li>
<li> %R &#8211; Heure au format 24 heures</li>
<li> %S &#8211; Secondes en tant que nombre décimal.</li>
<li> %t &#8211; Caractère tabulation.</li>
<li> %T &#8211; Heure courante, équivalent à %H:%M:%S</li>
<li> %u &#8211; Jour de la semaine en tant que nombre décimal [1,7], ou 1 représente le lundi.</li>
<li> %U &#8211; Le numéro de la semaine en nombre décimal, utilisant le premier dimanche en tant que premier jour de la première semaine.</li>
<li> %V &#8211; Le numéro de la semaine de l&#8217;année courante selon la norme ISO 8601:1988, de 01 à 53, ou la semaine 1 est la première semaine qui dispose au minimum de 4 jours dans l&#8217;année courante et ou Lundi est le premier jour de cette semaine.</li>
<li> %w &#8211; Jour de la semaine en tant que nombre décimal, dimanche étant 0</li>
<li> %W &#8211; Le numéro de la semaine de l&#8217;année courante en tant que nombre décimal, ou Lundi est le premier jour de la première semaine.</li>
<li> %x &#8211; Représentation préférée de la date selon les paramètres locaux.</li>
<li> %X &#8211; Représentation préférée de l&#8217;heure selon les paramètres locaux, sans la date.</li>
<li> %y &#8211; L&#8217;année en tant que nombre décimal, sans le siècle. (de 00 à 99)</li>
<li> %Y &#8211; L&#8217;année en tant que nombre décimal, avec le siècle.</li>
<li> %Z &#8211; Zone horraire, nom ou abréviation</li>
<li> %% &#8211; Un caractère litéral `%&#8217;</li>
</ul>
<h2>Lectures intéressantes sur Smarty:</h2>
<ul>
<li><a href="http://www.smarty.net/manual/fr/">Documentation officielle de Smarty (en français)</a></li>
<li><a href="http://eric-pommereau.developpez.com/tutoriels/initiation-smarty/">Initiation à Smarty par Eric Pommereau</a></li>
</ul>
<p>Pour aider à la rédaction de ma série d&#8217;articles, n&#8217;hésitez pas à laisser un commentaire sur un sujet que vous voudriez voir abordé, ou à me signaler des docs intéressantes sur Smarty, je me ferais un plaisir de les rajouter dans les lectures intéressantes <img src='http://www.php-experts.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80</feedburner:origLink></item>
		<item>
		<title>La commande screen sous Linux</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/8qDPnQDAZqs/la-commande-screen-sous-linux-104</link>
		<comments>http://www.php-experts.org/developpement-web/admin-serveur/la-commande-screen-sous-linux-104#comments</comments>
		<pubDate>Thu, 12 Feb 2009 01:33:52 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[Admin serveur]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[screen]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=104</guid>
		<description><![CDATA[Si comme moi, vous bossez régulièrement en ligne de commande sous Linux (en SSH sur un serveur dédié, par exemple), il doit vous arriver de devoir jongler entre deux applications, deux répertoires, deux scripts&#8230; Bref, si vous passez beaucoup de temps à switcher entre deux tâches, screen est fait pour vous.

Le principe de Screen
Screen est [...]]]></description>
			<content:encoded><![CDATA[<p>Si comme moi, vous bossez régulièrement en ligne de commande sous Linux (en SSH sur un serveur dédié, par exemple), il doit vous arriver de devoir jongler entre deux applications, deux répertoires, deux scripts&#8230; Bref, si vous passez beaucoup de temps à switcher entre deux tâches, <strong>screen</strong> est fait pour vous.<br />
<span id="more-104"></span></p>
<h2>Le principe de Screen</h2>
<p><strong>Screen</strong> est un utilitaire en ligne de commande qui permet de créer plusieurs shells virtuels qui tournent en parallèle. En l&#8217;utilisant, vous aurez donc accès à plusieurs &#8220;sessions&#8221;, comme si vous aviez lancé <strong>plusieurs clients SSH</strong>. </p>
<p>Enorme avantage, screen ne s&#8217;arrête pas quand votre connexion au serveur est coupée. En rouvrant votre session Unix normale, vous pourrez faire screen -r (Recover) pour retrouver toutes vos fenêtres exactement dans l&#8217;état où vous les avez laissées (les actions en cours ont continué, les scripts ne sont pas interrompus, etc).</p>
<p>Après une rapide installation (le package apt se nomme &#8220;screen&#8221;), l&#8217;utilitaire est directement utilisable. Tapez &#8220;screen&#8221;, rien ne se passe. Et pourtant tout est ok, on y est. Bienvenue dans le monde de screen. Faites ce que vous avez à faire, éditez par exemple le fichier /etc/hosts de votre machine. Tapez ensuite control+A, puis C (pour Create). Une nouvelle fenêtre virtuelle est créée. Vous vous retrouvez devant une invite de commande, sur un shell vierge. Et c&#8217;est là que les réjouissances commencent. Faites un ls, par exemple. Ensuite, un Control+A puis N (Next) vous permet de passer à la fenêtre suivante gérée par Screen.<br />
Toutes les commandes Screen sont composées de la combinaison Control+A puis une lettre (ou un chiffre).</p>
<p>Voici le menu :</p>
<ul>
<li><strong>Ctrl-a c</strong> 	Créer une nouvelle fenêtre (Create)</li>
<li><strong>Ctrl-a k</strong> 	Fermer la fenêtre en cours (Kill)</li>
<li><strong>Ctrl-a w</strong> 	Liste les fenêtres disponibles (Windows) &#8211; La fenêtre courante est repérée par une étoile.</li>
<li><strong>Ctrl-a 0-9</strong> 	Aller à la fenêtre N (Les chiffres sont dans la liste des fenêtres obtenue en faisant W)</li>
<li><strong>Ctrl-a n</strong> 	Aller à la fenêtre suivante (Next)</li>
<li><strong>Ctrl-a Ctrl-a</strong> 	Switche en mode &#8220;2 fenêtres&#8221; (ramène à la fenêtre précédemment affichée)</li>
<li><strong>Ctrl-a [</strong> 	Copier </li>
<li><strong>Ctrl-a ]</strong> 	Coller</li>
<li><strong>Ctrl-a ?</strong> 	Liste des commandes (Aide/Help)</li>
<li><strong>Ctrl-a Ctrl-\</strong> 	Quitter &#8220;screen&#8221;</li>
<li><strong>Ctrl-a d</strong> 	Détacher le process, en laissant la fenêtre ouverte</li>
</ul>
<h2>Le mode Copie de Screen</h2>
<p>Screen peut aussi vous permettre de copier/coller efficacement du texte entre deux fenêtres. Pour cela, ouvrez le mode copie en faisant Ctrl-A [ .<br />
Une fois dans le mode copie, vous pouvez déplacer le curseur à l'aide des touches H,J,K et L. La barre d'espace commence/arrête la sélection du texte. Ctrl-A ] servira alors à coller le texte copié dans le &#8220;presse-papiers&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/admin-serveur/la-commande-screen-sous-linux-104/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/admin-serveur/la-commande-screen-sous-linux-104</feedburner:origLink></item>
		<item>
		<title>Cache d’opcode: Alternative Php Cache (APC)</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/UGCAKs1SwKI/cache-dopcode-alternative-php-cache-apc-62</link>
		<comments>http://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62#comments</comments>
		<pubDate>Tue, 09 Dec 2008 17:23:58 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[accélérer site internet]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[opcode]]></category>
		<category><![CDATA[optimisation]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=62</guid>
		<description><![CDATA[Pour accélerer les performances d&#8217;un site internet, il existe de nombreuses pistes à suivre. Outre les recommandations d&#8217;optimisation de Yahoo, qui concernent surtout l&#8217;architecture d&#8217;une application Web, on peut aussi s&#8217;attaquer à des couches plus transparentes (et souvent complètement ignorées par les développeurs), comme l&#8217;étape de &#8220;compilation&#8221; du script en exécutable. Nous allons voir comment [...]]]></description>
			<content:encoded><![CDATA[<p>Pour accélerer les performances d&#8217;un site internet, il existe de nombreuses pistes à suivre. Outre les <a href="http://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8">recommandations d&#8217;optimisation de Yahoo</a>, qui concernent surtout l&#8217;architecture d&#8217;une application Web, on peut aussi s&#8217;attaquer à des couches plus transparentes (et souvent complètement ignorées par les développeurs), comme l&#8217;étape de &#8220;compilation&#8221; du script en exécutable. Nous allons voir comment APC (Alternative Php Cache) peut nous aider rapidement à <strong>accélérer des scripts php</strong>.<br />
<span id="more-62"></span></p>
<h2>L&#8217;opcode ?</h2>
<p>Oui, l&#8217;opcode. C&#8217;est le code généré par votre serveur Web (qui a dit <a href="http://www.php-experts.org/category/developpement-web/admin-serveur">Apache</a> ?) à partir de vos scripts PHP, après leur interprétation et leur compilation. Ce code est exécutable, et sa génération prend un certain temps. A chaque exécution d&#8217;un script, le serveur régénère cet opcode, perdant ainsi un temps précieux: quand votre script n&#8217;a pas été modifié, cette étape est totalement inutile. On peut l&#8217;éviter en mémorisant l&#8217;opcode grâce à un <strong>cache d&#8217;opcode</strong>&#8230;<br />
Attention, il ne faut pas confondre les caches d&#8217;opcode et les caches HTML: un cache HTML servira à envoyer directement la sortie d&#8217;un script au client, sans traitement. Le cache d&#8217;opcode, lui, laisse place à l&#8217;exécution proprement dite du script dans des conditions normales: les données provenant d&#8217;une <a href="http://www.php-experts.org/category/bases-de-donnees/mysql">base de données MySQL</a>, par exemple, seront rapatriées comme à l&#8217;accoutumée. On ne perd donc aucune réactivité au niveau de l&#8217;application, tout en améliorant ses temps de réponse.</p>
<h2>APC ? (Alternative Php Cache)</h2>
<p>Oui, APC. APC est un projet libre, implémenté comme une extension Zend. Cela permet de le compiler dans PHP ou de l&#8217;intégrer plus tard, comme un module classique. Le principal avantage d&#8217;APC (et des autres caches d&#8217;opcode) est qu&#8217;il n&#8217;y a aucun besoin en terme de modification des scripts: il suffit d&#8217;installer et d&#8217;activer le module pour que celui-ci accélère vos scripts PHP. De ce côté là, donc, rien de spécial à ajouter.<br />
APC permet, par un script d&#8217;administration, de suivre quels opcodes sont mis en cache, le nombre de hits économisés, ainsi que les données utilisateur. Très pratique, la colonne &#8220;miss&#8221; vous indique combien de scripts ont été appelés sans profiter de l&#8217;accélération d&#8217;APC (Cela peut arriver car vous pouvez mettre des filtres en place pour ne stocker que certains répertoires, ou limiter la taille en mémoire occupée par l&#8217;ensemble des scripts &#8220;compilés&#8221;, par exemple&#8230;)</p>
<h2>Le cache de données utilisateur</h2>
<p>Mais là où réside, selon moi, la vraie puissance d&#8217;APC, est dans son cache de données utilisateur. En effet, imaginons le cas où nous avons une requête SQL assez lourde, suivie d&#8217;un traitement assez conséquent: sur la page d&#8217;accueil d&#8217;un <a href="http://www.forumfr.com/">forum</a> (lien-copinage), on souhaite afficher les derniers connectés et le nombre de messages qu&#8217;ils ont posté. En théorie, à chaque affichage de la page, on va réexécuter la requête, et donc assassiner bêtement le serveur SQL.<br />
On pourrait stocker les données dans une Session PHP ? Oui, mais d&#8217;une, les sessions ne sont pas faites pour ça, et de deux, on exécuterait quand même la requête SQL et le traitement associé pour chaque nouveau connecté.<br />
La meilleure solution reste alors d&#8217;utiliser le cache de données d&#8217;APC. On va pour cela se servir de la fonction apc_store, qui prend 3 paramètres :<br />
bool apc_store  ( string $key  , mixed $var  [, int $ttl  ] )</p>
<ul>
<li><em>$key</em> est le nom que l&#8217;on souhaite donner à la variable dans le &#8220;magasin&#8221; (store) d&#8217;APC. Je vous conseille de la préfixer du nom du site concerné si vous hébergez plusieurs sites sur le même serveur ; les variables sont accessibles à tous les scripts (attention donc à ce que vous faites dans le cas d&#8217;un hébergement partagé&#8230; ne stockez de préférence aucune donnée &#8220;sensible&#8221; à moins de savoir précisément ce que vous faites).</li>
<li><em>$var</em> est la valeur à stocker, qui peut être un nombre, une chaîne, un tableau, ou même un objet complet (Attention, dans ce dernier cas, à bien inclure la déclaration de classe de l&#8217;objet avant d&#8217;essayer de le récupérer&#8230;).</li>
<li><em>$ttl</em> est le &#8220;Time To Live&#8221; de la variable, c&#8217;est à dire le temps en secondes avant qu&#8217;APC ne l&#8217;efface de son store.</li>
</ul>
<p>Par exemple, dans le cadre de notre forum, on aurait quelque chose comme :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">apc_store<span class="br0">&#40;</span><span class="st0">&#8216;forum_derniers_connectes&#8217;</span>,<span class="re0">$derniersConnectes</span>,<span class="nu0">60</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Ce qui signifie qu&#8217;on stocke, tel quel, le tableau (array) $dernierConnectes, sous le nom forum_derniers_connectes, pour une durée de 60 secondes.</p>
<p>Pour accéder à la variable, on dispose de la fonction apc_fetch, qui prend le $key de la variable en paramètre, et renvoie soit la valeur stockée, soit FALSE en cas d&#8217;échec. On peut donc faire :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="re0">$derniersConnectes</span> = apc_fetch<span class="br0">&#40;</span><span class="st0">&#8216;forum_derniers_connectes&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// forum_derniers_connectes n&#8217;est pas présent dans le cache: il faut le calculer</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$derniersConnectes</span> = get_derniers_connectes<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// boum, on exécute</span></div>
</li>
<li class="li1">
<div class="de1">apc_store<span class="br0">&#40;</span><span class="st0">&#8216;forum_derniers_connectes&#8217;</span>,<span class="re0">$derniersConnectes</span>,<span class="nu0">60</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>C&#8217;est tout ! Si APC trouve la variable, il renseigne $derniersConnectes. Dans le cas contraire, on rapatrie les infos et on les stocke pour 60 secondes. La requête-de-la-mort ne sera plus exécutée qu&#8217;une fois par minute.</p>
<h2>Bénéfices</h2>
<p>Le bénéfice est donc double: on économise à la fois sur le temps d&#8217;exécution des scripts en ne les compilant qu&#8217;au besoin grâce au <strong>cache d&#8217;opcode</strong> (d&#8217;environ 50% selon les auteurs, sachant que cela dépendra de la complexité du script&#8230; on gagnera beaucoup plus sur des algorithmes récursifs, notamment), mais aussi sur le temps de processing de certaines ressources grâce au <strong>cache de données</strong>, qui est utilisé ici pour des requêtes SQL mais qui pourrait aussi bien l&#8217;être pour la lecture du fichier de configuration de votre application, par exemple (en stockant, au choix, un tableau associatif ou un objet $config), ou de n&#8217;importe quelle variable qui n&#8217;a pas vraiment besoin d&#8217;être mise à jour en temps réel.</p>
<h2>Liens utiles</h2>
<p><a href="http://fr.php.net/apc">Manuel APC sur php.net</a> (en français)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62</feedburner:origLink></item>
		<item>
		<title>Parser des XML volumineux avec XMLReader</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/TUyneDwNGu8/parser-des-xml-volumineux-avec-xmlreader-42</link>
		<comments>http://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42#comments</comments>
		<pubDate>Fri, 28 Nov 2008 17:25:20 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[domdocument]]></category>
		<category><![CDATA[objet]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[simplexml]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xmlreader]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=42</guid>
		<description><![CDATA[Avec des classes comme DomDocument ou SimpleXML, le parsing de fichiers XML s&#8217;est considérablement simplifié en PHP 5. Mais quand on doit parser des fichiers très volumineux (comme j&#8217;ai eu à le faire récemment pour le catalogue produits de mon comparateur d&#8217;électroménager), on se retrouve très rapidement avec des scripts très gourmands en mémoire. En [...]]]></description>
			<content:encoded><![CDATA[<p>Avec des classes comme <strong>DomDocument</strong> ou <strong>SimpleXML</strong>, le parsing de fichiers XML s&#8217;est considérablement simplifié en PHP 5. Mais quand on doit parser des fichiers très volumineux (comme j&#8217;ai eu à le faire récemment pour le catalogue produits de mon <a href="http://www.achat-electromenager.org/">comparateur d&#8217;électroménager</a>), on se retrouve très rapidement avec des scripts très gourmands en mémoire. En effet, ces classes lisent et analysent la totalité du fichier XML avant de pouvoir agir dessus. Ce n&#8217;est pas le cas de <strong>XMLReader</strong>, qui elle, fonctionne en mode flux: le fichier est alors lu au fur et à mesure des besoins. Il en résulte des scripts plus rapides et très peu consommateurs de RAM.<br />
<span id="more-42"></span></p>
<h2>Utiliser XMLReader et SimpleXML de concert</h2>
<p>Voici comment on procède:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$xml</span> = <span class="kw2">new</span> XMLReader<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$xml</span>-&gt;<span class="me1">open</span><span class="br0">&#40;</span><span class="st0">&#8216;gros_fichier.xml&#8217;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$xml</span>-&gt;<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$xml</span>-&gt;<span class="me1">nodeType</span> == XMLREADER::<span class="me2">ELEMENT</span> &amp;amp;&amp;amp; <span class="re0">$xml</span>-&gt;<span class="me1">localName</span> == <span class="st0">&quot;product&quot;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$product</span> = <span class="re0">$xml</span>-&gt;<span class="me1">expand</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$product</span> = <span class="kw2">new</span> SimpleXMLElement<span class="br0">&#40;</span><span class="st0">&#8216;&lt;product&gt;&#8217;</span>.<span class="re0">$xml</span>-&gt;<span class="me1">readInnerXML</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="st0">&#8216;&lt;/product&gt;&#8217;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$prod</span><span class="br0">&#91;</span><span class="st0">&#8216;name&#8217;</span><span class="br0">&#93;</span> = <a href="http://www.php.net/utf8_decode"><span class="kw3">utf8_decode</span></a><span class="br0">&#40;</span><span class="re0">$product</span>-&gt;<span class="me1">name</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Ligne 1, on instancie classiquement un objet XMLReader. Le constructeur ne prend pas de paramètres. Ligne 2, on assigne le fichier que l&#8217;on souhaite parser.<br />
C&#8217;est ensuite que les joyeusetés commencent : $xml-&gt;read() permet de passer au node suivant. Tant que XMLReader trouvera des nodes, on continuera <strong>à lire le fichier séquentiellement</strong>. L&#8217;intérieur de la boucle contiendra le traitement que je souhaite effectuer sur chaque node. Ici, si le nodeType est &#8220;ELEMENT&#8221; si le localName (le libellé du tag) est &#8220;product&#8221;, nous sommes en présence de l&#8217;un des produits que je souhaite traiter.<br />
Dans ce cas, $xml-&gt;expand() permet de copier le node courant afin de le manipuler plus aisément. L&#8217;astuce ligne 6 (j&#8217;imagine bien qu&#8217;il doit y avoir un moyen de faire ça beaucoup plus proprement) consiste à recréer le node à partir de son localName et de la chaîne de caractères au format XML qu&#8217;il contient, récupérée grâce à $xml-&gt;readInnerXML(). Etant habitué à l&#8217;utilisation courante de SimpleXML, et pour des raisons de confort personnel, je passe la chaîne de caractères obtenue en paramètre au constructeur de SimpleXMLElement afin de récupérer un élement XML classique, que j&#8217;utilise ensuite simplement en accédant aux données qu&#8217;il contient.</p>
<h2>Vérifier le bon déroulement des opérations</h2>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$i</span>++;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="re0">$i</span> % <span class="nu0">500</span><span class="br0">&#41;</span> == <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;$i &#8211; Ok<span class="es0">\r</span><span class="es0">\n</span>&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/flush"><span class="kw3">flush</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Pour les imports de gros fichiers (1.2 giga-octets dans mon cas), mieux vaut savoir exactement ce qu&#8217;il se passe. J&#8217;ai donc déclaré avant mon while une variable $i=0, que j&#8217;incrémente à la fin de ma boucle, après avoir traité un produit. Ligne 2, je vérifie que $i (le nombre de produits traités) est un multiple de 500. Si oui, j&#8217;affiche le nombre courant et le flush() permet d&#8217;envoyer immédiatement le contenu du buffer à la sortie du script. Ici, le but était de faire tourner le script en ligne de commandes (CLI), mais cela aurait aussi bien marché avec un navigateur. (Il aurait fallu remplacer les \r\n par un &lt;br /&gt; classique.<br />
<br />
Si cet article vous a intéressé, j&#8217;apprécierais un peu de promotion : <img src='http://www.php-experts.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><script>scoopeo_url='http://www.php-experts.org/developpement-web/php-developpement-web-2/parser-des-xml-volumineux-avec-xmlreader-42'</script><script language='javascript' src='http://scoopeo.com/clicker/insert/small'></script></p>
<hr />
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42</feedburner:origLink></item>
		<item>
		<title>Apache, VirtualHost et ServerAlias</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/Z9B7BaqefNc/apache-virtualhost-et-serveralias-26</link>
		<comments>http://www.php-experts.org/developpement-web/admin-serveur/apache-virtualhost-et-serveralias-26#comments</comments>
		<pubDate>Mon, 20 Oct 2008 21:26:17 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[Admin serveur]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[vhost]]></category>
		<category><![CDATA[virtual host]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=26</guid>
		<description><![CDATA[Lorsqu&#8217;on adapte la configuration d&#8217;un serveur Apache pour gérer un nouveau domaine, il faut théoriquement créer autant de VirtualHosts que ce qu&#8217;on aura de sous-domaines. Et si chaque utilisateur enregistré devait avoir son propre sous-domaine (comme sur une plate-forme de blogs, par exemple) ?

Rien de plus simple, en fait&#8230; La directive ServerAlias permet d&#8217;utiliser des [...]]]></description>
			<content:encoded><![CDATA[<p>Lorsqu&#8217;on adapte la configuration d&#8217;un serveur Apache pour gérer un nouveau domaine, il faut théoriquement créer autant de VirtualHosts que ce qu&#8217;on aura de sous-domaines. Et si chaque utilisateur enregistré devait avoir son propre sous-domaine (comme sur une plate-forme de blogs, par exemple) ?<br />
<span id="more-26"></span><br />
Rien de plus simple, en fait&#8230; La directive ServerAlias permet d&#8217;utiliser des wildcards, pour désigner &#8220;tous les sous-domaines&#8221;. L&#8217;étoile (*) fonctionne alors comme une parenthèse capturante dans une expression régulière. La directive VirtualDocumentRoot, elle, accepte des paramètres en %N (où N est un nombre entier), avec N correspondant à la place de l&#8217;étoile dans la chaîne. %1 est la première chaîne qui a matché une étoile. </p>
<p>Pas clair ? Ok, un exemple :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">&lt;VirtualHost *&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ServerName domain.tld</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ServerAlias *.domain.tld</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; VirtualDocumentRoot /var/www/domain.tld/%<span class="nu0">1</span>/</div>
</li>
<li class="li2">
<div class="de2">&lt;/VirtualHost&gt;</div>
</li>
</ol>
</div>
<p>Pas plus compliqué&#8230; Le * va capturer le sous-domaine et le passer au VirtualDocumentRoot. Donc pour test.domain.tld, on tombera dans /var/www/domain.tld/test/.</p>
<p>Dans le &lt;VirtualHost&gt;, après un VirtualDocumentRoot, on peut utiliser des directives <Directory> comme d&#8217;habitude. (Je n&#8217;ai pas essayé d&#8217;y reprendre le %1, pour modifier les options de configuration de l&#8217;ensemble des dossiers &#8220;virtuels&#8221;&#8230;  quelqu&#8217;un sait si ça marche ?)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/admin-serveur/apache-virtualhost-et-serveralias-26/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/admin-serveur/apache-virtualhost-et-serveralias-26</feedburner:origLink></item>
		<item>
		<title>Changer d’hébergement : la migration de sites web</title>
		<link>http://feedproxy.google.com/~r/php-experts-org-developpement-php-internet/~3/gLW7dYc53BQ/changer-hebergement-migration-site-web-25</link>
		<comments>http://www.php-experts.org/developpement-web/changer-hebergement-migration-site-web-25#comments</comments>
		<pubDate>Fri, 03 Oct 2008 17:40:43 +0000</pubDate>
		<dc:creator>Didier</dc:creator>
				<category><![CDATA[Développement Web]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.php-experts.org/?p=25</guid>
		<description><![CDATA[Vous avez un petit serveur sur lequel vous hébergez vos sites. Ces derniers ont grandi, grandi, et il est temps de prendre un serveur plus puissant, et donc de déplacer vos scripts et vos bases de données. C&#8217;est vrai, aucune compétence poussée des shells Unix n&#8217;est obligatoire ; vous pouvez très bien tout faire avec [...]]]></description>
			<content:encoded><![CDATA[<p>Vous avez un petit serveur sur lequel vous hébergez vos sites. Ces derniers ont grandi, grandi, et il est temps de prendre un serveur plus puissant, et donc de déplacer vos scripts et vos bases de données. C&#8217;est vrai, aucune compétence poussée des shells Unix n&#8217;est obligatoire ; vous pouvez très bien tout faire avec un client FTP et phpMyAdmin (par exemple). Mais cela suppose de tout copier de la machine A (le &#8220;petit&#8221; serveur) vers votre poste de travail, puis, de là, de tout envoyer, depuis votre poste, vers la machine B. En faisant tout depuis une ligne de commande, on supprime un intermédiaire. Laissons les machines s&#8217;arranger entre elles&#8230;<br />
<span id="more-25"></span><br />
<em>(Note: je travaille habituellement sous Linux Debian. Pour d&#8217;autres systèmes/distributions, il faudra sûrement adapter les options des utilitaires utilisés. La marche à suivre restera valable)</em></p>
<p><em>(Note en réaction au commentaire de Laurentj :<br />
Ce billet s&#8217;adresse à des développeurs web hébergés sur des serveurs en ayant un accès SSH, et ayant conscience des problématiques de gestion d&#8217;un serveur.<br />
L&#8217;administration système, à fortiori sur une machine connectée 24/7, est un métier à part entière, qui requiert évidemment des compétences poussées ; ne pas savoir ce que l&#8217;on fait peut être <strong>lourd de conséquences</strong>.<br />
Les commandes présentées ici sont très simples et ce post est plus destiné à servir de &#8220;pense-bête&#8221; que de véritable tutoriel.)</em><br />
Il va falloir copier les scripts et les bases de données. En supposant que vous utilisez MySQL, voici la procédure à suivre.</p>
<p>Pour copier les scripts, on va compresser le DocumentRoot de chaque site dans une archive tarball (.tar.gz ou .tgz). On prendra le soin d&#8217;inclure à l&#8217;archive le dump de la base de données utilisée par le site. On n&#8217;aura ainsi qu&#8217;un seul fichier à envoyer et &#8220;installer&#8221; sur le serveur B. Ainsi, on est sûrs de ne rien oublier, et la compression diminue évidemment le temps qui sera nécessaire pour le transfert.</p>
<p>Vu qu&#8217;on ne travaille JAMAIS sur un site qui est -pour quelques minutes encore- en production (merci de noter ça en rouge dans vos petits cahiers), on commence par créer une copie de ce dossier dans ~/backup. Le ~ signifie &#8220;répertoire /home de l&#8217;utilisateur courant&#8221;. Pour ce faire :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">cp</span> -R <span class="br0">&#91;</span>document_root<span class="br0">&#93;</span>/ ~/backup</div>
</li>
</ol>
</div>
<p>Où -R signifie récursif: copier aussi les sous-répertoires.</p>
<p>Passons ensuite dans le répertoire de backup :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw3">cd</span> ~/backup</div>
</li>
</ol>
</div>
<p>On réalise un dump (sauvegarde) de la base de données (attention, je parle bien ici d&#8217;une seule base, et pas du contenu complet du serveur&#8230;)</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">mysqldump -h localhost -u <span class="br0">&#91;</span>utilisateur<span class="br0">&#93;</span> -p <span class="br0">&#91;</span>nom_de_la_base<span class="br0">&#93;</span> &gt; <span class="br0">&#91;</span>nom_du_fichier<span class="br0">&#93;</span>.sql</div>
</li>
</ol>
</div>
<p>où :</p>
<ul>
<li> [utilisateur] est le nom d&#8217;un user SQL qui a les privilèges en lecture sur la base</li>
<li> [nom_de_la_base] est la base qu&#8217;on souhaite copier</li>
<li> [nom_du_fichier] est le nom du fichier dans lequel sera stocké le dump (choisir un fichier qui n&#8217;existe pas&#8230;)</li>
</ul>
<p>Il vous sera demandé (grâce à l&#8217;option -p) d&#8217;entrer le mot de passe associé à ce compte-utilisateur.</p>
<p>Et c&#8217;est parti pour la création du tarball :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">tar</span> cvzf ../<span class="br0">&#91;</span>nom_de_l_archive<span class="br0">&#93;</span>.tgz .</div>
</li>
</ol>
</div>
<p>[nom_de_l_archive] étant le nom du fichier que vous voulez créer.<br />
.. signifie &#8220;un répertoire plus haut dans l&#8217;arborescence&#8221;, donc dans le /home de l&#8217;user courant.</p>
<p>On peut vérifier que l&#8217;archive est bien formée et comprend bien les fichiers escomptés. Ca ne mange pas de pain et peut éviter de grosses crises d&#8217;hystérie quand on s&#8217;est raté quelque part. Listons donc le contenu de l&#8217;archive (pensez à remonter d&#8217;un cran dans l&#8217;arbo):</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">tar</span> -tvf <span class="br0">&#91;</span>archive<span class="br0">&#93;</span></div>
</li>
</ol>
</div>
<p>On peut ensuite copier par SCP l&#8217;archive sur le nouveau serveur (machine B):</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">scp</span> <span class="br0">&#91;</span>nom_du_fichier<span class="br0">&#93;</span>.tgz <span class="br0">&#91;</span>user<span class="br0">&#93;</span>@<span class="br0">&#91;</span><span class="kw2">hostname</span><span class="br0">&#93;</span>:~</div>
</li>
</ol>
</div>
<ul>
<li>[nom_du_fichier] étant le nom du dump généré juste au-dessus</li>
<li> [user] étant un utilisateur existant sur la machine B</li>
<li> [hostname] étant un nom de domaine qui pointe vers B, ou son adresse IP</li>
</ul>
<p>Le ~ (tilde) veut toujours dire &#8220;dans le répertoire /home&#8221; de l&#8217;utilisateur (mais sur le nouveau serveur, cette fois). Vous pouvez indiquer n&#8217;importe quel path pour lequel l&#8217;user spécifié à le droit d&#8217;écrire (pensez à bien inclure le premier slash)</p>
<p>On aurait pu faire le dump directement depuis le nouveau serveur, à condition qu&#8217;on puisse se connecter au serveur MySQL de l&#8217;ancien depuis le réseau (bind-adress *) mais le dump prendrait plus de temps. Donc autant le réaliser directement depuis la machine A et l&#8217;envoyer avec le reste du site.</p>
<p>On passe ensuite en SSH sur la machine B. La connexion à la machine A ne servira plus ; on la coupe (une larme d&#8217;émotion est permise pour les nostalgiques).<br />
On décompresse notre archive magique :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">mkdir</span> site</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">tar</span> vxcf archive.tgz site/</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">cd</span> site</div>
</li>
</ol>
</div>
<p>On se connecte au serveur MySQL et on crée la base de données qui va recevoir le dump :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">mysql -u root -p</div>
</li>
</ol>
</div>
<p>create database [nom_de_la_base]<br />
On monte la base de données dans le serveur MySQL.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1">mysql -u root -p <span class="br0">&#91;</span>nom_de_la_base<span class="br0">&#93;</span> &lt; <span class="br0">&#91;</span>dump<span class="br0">&#93;</span>.sql</div>
</li>
</ol>
</div>
<p>Où [dump] est le nom du dump qu&#8217;on a transféré et décompressé.</p>
<p>La base est prête ! (Pensez, si besoin, à recréer les utilisateurs MySQL qui auront les accès nécessaires sur cette base)<br />
On crée alors le DocumentRoot du site, et on s&#8217;y rend pour y déplacer les fichiers décompressés :</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">mkdir</span> /var/www/<span class="br0">&#91;</span>site<span class="br0">&#93;</span>/</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">cd</span> /var/www/<span class="br0">&#91;</span>site<span class="br0">&#93;</span>/</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">mv</span> -R ~/backup/ .</div>
</li>
</ol>
</div>
<p>C&#8217;est fait. Vous pouvez vérifier que tout fonctionne en modifiant votre fichier hosts sous Windows : Editez le avec Notepad et ajoutez la ligne &#8220;[nouvelle_ip] [www.domain.tld]&#8220;. Si vous utilisez Internet Explorer, fermez et rouvrez votre navigateur (pour que les modifications soient prises en compte) et allez voir votre site. Tout marche ? Il ne vous reste plus qu&#8217;à changer vos DNS&#8230; Migration de site accomplie ! <img src='http://www.php-experts.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Bien sur, en faisant comme cela, vous &#8220;perdrez&#8221; les données entre le moment où vous faites le dump et celui où les DNS basculent effectivement. Vous pouvez, une fois les DNS basculés, faire une extraction des données de la base &#8220;à la mano&#8221; (un différentiel qu&#8217;on appelle souvent un Delta&#8230;) mais c&#8217;est une autre histoire&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.php-experts.org/developpement-web/changer-hebergement-migration-site-web-25/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.php-experts.org/developpement-web/changer-hebergement-migration-site-web-25</feedburner:origLink></item>
	</channel>
</rss>
