Archive pour la catégorie ‘PHP & MySQL’

Bench PHP en dessert

Mercredi 8 février 2006 | PHP & MySQL

Puisque cela faisait longtemps...

Php et Echo

Il est plus performant d'écrire :

echo '<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta name="description" content="';
echo $meta_description;
echo '" />
<meta name="keywords" content="';
echo $meta_keywords;
echo '" />
<link rel="alternate" type="application/rss+xml" title="';
echo $rss_title;
echo ' RSS" href="rss.php" />
<link rel="alternate" type="application/rss+xml" title="';
echo $rss_title;
echo ' RSS 2.0" href="rss2.php" />
<link rel="shortcut icon" type="images/x-icon" href="favicon.ico" />
<meta name="DC.title" content="';
echo $title;
echo '" /></head>';

... que d'écrire :

echo '<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta name="description" content="'.$meta_description.'" />
<meta name="keywords" content="'.$meta_keywords.'" />
<link rel="alternate" type="application/rss+xml" title="'.$title.' RSS" href="rss.php" />
<link rel="alternate" type="application/rss+xml" title="'.$title.' RSS 2.0" href="rss2.php" />
<link rel="shortcut icon" type="images/x-icon" href="favicon.ico" />
<meta name="DC.title" content="'.$title.'" /></head>';

Ceci provient de la concaténation préalable de la chaîne de caractères à afficher. On pourrait préjuger qu'une somme d'instructions multiples (echo ici même) nuirait aux performances. Or la première solution s'en sort un peu mieux. Moralité, si vous avez de longues chaînes aux pieds, allez-y petit à petit, au lieu de tout concaténer. Bien sûr il s'agit là encore d'une optimisation au niveau atomique, il y a bien d'autres façons de miner un script au C4.

MySQL 5.0

Jeudi 27 octobre 2005 | PHP & MySQL
MySQL 5

MySQL 5.0 est de sortie. Un bon nombre d'améliorations le placent désormais comme un moteur de base de données chatouillant le mammouth Oracle. Notamment :

  • Les vues
  • Les curseurs
  • Les procédures stockées
  • Un mode SQL Strict
  • Un type BIT pour remplacer TINYINT(1)
  • La base d'information INFORMATION_SCHEMA, qui s'apparente à un catalogue de métadonnées (comme ce qui existe déjà sous Oracle)
  • Le daemon MySQL Instance Manager pour administrer et monitorer les instances en cours d'exécution
  • Une nouvelle librairie mathématique de précision
  • De nouveaux moteurs de stockage : ARCHIVE qui est destiné comme son nom l'indique au stockage de données à long terme, avec compression mais sans index; et FEDERATED qui permet l'accès à des tables distantes
  • Les déclencheurs (triggers) qui permettent de déclencher une action lorsqu'un événement se produit
  • L'augmentation à 65 532 octets de la longueur maximum du type VARCHAR
  • Des améliorations au niveau des transactions, des performances (pour NOT IN, VARCHAR, BIT, COUNT(DISTINCT), MAX et MIN avec GROUP BY, WHERE multiples, jointures, moteur InnoDB...)
  • Utilisation des index lors de requêtes DELETE ou UPDATE avec clause ORDER BY ... LIMIT

MySQL AB reproduit la chasse aux bugs déjà expérimentée par la fondation Mozilla. Il est possible cette fois-ci de gagner 8 iPod nano. Le troll du jour est : "Est-ce que PostgreSQL a encore quelque chose de plus ?"

Process Kill0r

Mardi 2 novembre 2004 | PHP & MySQL

Encore du PHP pour un script de fainéant qui kill les processus indésirables sous windows (pratique avant de lancer une application qui nécessite beaucoup de ressources). A customiser selon vos envies. A titre culturel, shell_exec exécute une commande et retourne le résultat dans une chaîne. On se sert ici de la commande tasklist qui dresse une liste des processus lancés. Si une des lignes contient le nom d'un exécutable concerné, le signal d'arrêt lui est envoyé avec taskkill /IM. L'option /F force la fin si celle-ci prend son temps.

Kill Process
<?php

/* Process Kill0r 1.0 by dew */

$str=shell_exec("tasklist");
$str=explode("\n",$str);

$process=array(
    'Apache.exe', // Apache
    'mysqld-nt.exe', // MySQL
    'Winamp.exe', // Winamp
    'atiptaxx.exe', // Control Panel ATI
    'ati2evxx.exe', // Encore de l'ATI
    'tablet.exe', // Tablette graphique
    'TabUserW.exe', // Tablette graphique
    'wmiprvse.exe', // Windows Management Thing
    'cthelper.exe', // Creative Thing
    'uphclean.exe', // Fast session close
    'spoolsv.exe', // Spool Impression
    'supercopier.exe', // SuperCopier
    'ctfmon.exe', // Microsoft Language Thing
);

foreach($str as $ligne) {
    foreach($process as $p) {
        if(preg_match('/'.$p.'/i',$ligne)) {
            exec("taskkill /IM $p /F");
        }
    }
}

?>

A lancer avec la commande php.exe -q script.php (si le chemin est spécifié dans PATH, etc...).

Fini le geek stuff, demain on reprend avec de la philo, promis.

Optimisation PHP le retour : strtr vs str_replace

Lundi 1 novembre 2004 | PHP & MySQL
PHP

Pour remplacer des mots précis dans une chaîne de texte il existe plusieurs méthodes. Les plus évidentes sont :

  • La fonction strtr associée à un tableau contenant les chaînes à traduire.
  • Une simple série de str_replace.

Exemple pratique avec des BBtags :

Le tableau d'éléments à remplacer pour strtr :

$arr=array('[/#]'=>'</span>', '[b]'=>'<b>', '[/b]'=>'</b>', '[i]'=>'<i>', '[/i]'=>'</i>', '[quote]'=>'<blockquote>', '[/quote]'=>'</blockquote>');

Le texte de test bidon :

$texte='In a [b]recent article[/b], former TRG CEO Jeff V. Merkey had offered to pay [i]50K USD for a BSD-licensed[/i] Linux. [quote]Groklaw did a followup on his offer[/quote], to which [#red]Jeff responded by notifying the FBI of Groklaws hate crimes violation[/#]. Merkey doesnt exactly have a great record, either, which is made even more apparent by his recent threats to file suit against Merkey.net for slander and [i]trademark infringement[/i], amongst others. In addition, he has also reported [b]Merkey.net[/b] to the FBIs hate crime department. What could Merkey.net do to get Jeff V. Merkey off their backs ?';

Avec str_replace :

$texte=str_replace('[/#]','</span>',$texte);
$texte=str_replace('[b]','<b>',$texte);
$texte=str_replace('[/b]','</b>',$texte);
$texte=str_replace('[i]','<i>',$texte);
$texte=str_replace('[/i]','</i>',$texte);
$texte=str_replace('[quote]','<blockquote>',$texte);
$texte=str_replace('[/quote]','</blockquote>',$texte);

Avec strtr :

$texte=strtr($texte,$arr);

Résultat sur 10000 itérations (temps en millisecondes) :

str_replace vs strtr

Conclusion : str_replace reste la solution la plus performante même si l'écriture est plus longue et moins souple.

Mise à jour : Sur la suggestion de Romain, la solution exploitant des tableaux avec str_replace mérite encore plus d'attention.

str_replace avec tableau :

$pattern = array('[b]', '[/b]', '[i]', '[/i]');
$repl = array('<b>', '</b>', '<i>', '</i>');
$texte = str_replace( $pattern, $repl, $texte);

str_replace vs str_replace

Dotclear a un petit fumet de gruyère

Lundi 20 septembre 2004 | PHP & MySQL
Gruyère

Dotclear est touché par une faille de sécurité, dans toutes ses versions. Il est recommandé à tous ceux qui utilisent ce très bon script de le mettre à jour vers la version 1.2 RC2 ou d'appliquer un correctif car toutes les versions sont touchées.

Toutes les infos sont dans l'annonce sur le forum Dotclear. Quoiqu'il en soit, le must est toujours de faire un dump régulier de la db pour pouvoir tout récupérer au cas où.

Allez Olivier on te pardonne :)

mysql_fetch_row vs mysql_fetch_array

Samedi 28 août 2004 | PHP & MySQL
MySQL

Choisir entre les deux fonctions PHP mysql_fetch_row() et mysql_fetch_array() peut sembler anodin, mais c'est une question souvent posée et qui a déjà donné lieu à de nombreux débats.

A première vue les descriptions de la documentation PHP peuvent indiquer une piste :

  • mysql_fetch_array : Retourne une ligne de résultat MySQL sous la forme d'un tableau associatif, d'un tableau indexé, ou les deux
  • mysql_fetch_row : Retourne une ligne de résultat MySQL sous la forme d'un tableau

On peut constater que la première méthode nécessite plus de traitement car elle renvoie un tableau associatif, c'est à dire en utilisant les noms des champs comme indices. Généralement on peut apercevoir ceci :

$result=mysql_query('SELECT nom_du_champ1,nom_du_champ2 FROM table');
while($array=mysql_fetch_array($result)) {
  /* utilisation de $array['nom_du_champ1']... ; */
}

Déjà, le fait d'associer les noms des champs dans le tableau nécessite un investissement en ressources plus important. Des indices sous forme de chaînes de caractères seront plus longs à traiter que des simples valeurs numériques.

La seconde méthode est donc plus légère. Principalement car elle ne retourne qu'un tableau indexé numériquement. Mais comment l'utiliser de la meilleure manière ? L'inconvénient est de devoir s'y retrouver entre cette indexation numérique et les noms habituels des champs, spécialement lorsque la structure de la table peut changer au cours du temps (ajout, modification ou suppression de champs). Néanmoins on peut contourner cette limitation de deux façons :

  • Pour s'affranchir d'une potentielle modification des champs, de leur ordre dans la table : spécifier clairement dans la requête (ici SELECT) les champs à prendre en compte. Au-delà de l'aspect pratique cela est conseillé pour obtenir de meilleures performances, surtout lorsque la table contient beaucoup de champs différents qui ne seront pas forcément utiles.
  • Pour s'affranchir du nom des colonnes : utiliser l'élément de langage list() qui permet de rassembler les variables sous forme de tableau, pour les assigner en une seule ligne.
$result=mysql_query('SELECT nom_du_champ1,nom_du_champ2 FROM table');
while(list($champ1,$champ2)=mysql_fetch_array($result)) {
  /* utilisation de $champ1, $champ2... ; */
}

Pourtant, il est précisé dans la doc que :

Il est important de souligner que mysql_fetch_array() n'est PAS significativement plus lente que mysql_fetch_row(), tandis qu'elle ajoute un confort d'utilisation important.

A cela il faut rajouter que 3 cas de figure se présentent alors, avec l'ajout de la fonction mysql_fetch_assoc(), classés du plus rapide au plus lent :

  1. mysql_fetch_row() : tableau d'indices numériques ($array[1])
  2. mysql_fetch_assoc() : tableau associatif ($array['nom_du_champ'])
  3. mysql_fetch_array() : tableau d'indices numériques + tableau associatif

En gros, mysql_fetch_array effectue le travail des deux premières simultanément. Donc tant qu'à choisir, autant le faire entre row et assoc. Il existe de surcroît deux outsiders :

Là encore il s'agit d'une optimisation au niveau atomique. Il est inutile de reprendre tous vos scripts pour remplacer l'une ou l'autre fonction. Rien n'empêchera la totalité de la boucle de prendre du temps si la requête est mal constituée. Ceci fera l'objet d'un prochain sujet de discussion :)

PHP comme langage générique

Jeudi 19 août 2004 | PHP & MySQL
PHP ROX

Un article du Linuxjournal : PHP as a General-Purpose Language propose d'utiliser PHP dans d'autres domaines que celui où il exhibe ses biceps : le web.

Car PHP possède toutes les caractéristiques d'un langage généraliste qui peut être utile dans un bon nombre d'environnements. Dans cet article, Marco Tabini illustre la façon de procéder pour utiliser la version en ligne de commande et effectuer des opérations complexes dans le shell, comme manipuler des fichiers, lire et parser des documents XML (ici un feed RSS), gérer des tâches avec cron...

Aide-mémoire d'éléPHPant

Lundi 19 juillet 2004 | PHP & MySQL
Elephant PHP

Quelques toutes petites fonctions aide-mémoire PHP, qui me sont utiles depuis quelques années :

function getmicrotime() {
 $mtime=microtime();
 $mtime=explode(' ',$mtime);
 $mtime=$mtime[1] + $mtime[0];
 return $mtime;
}

Renvoie un temps local du serveur en microsecondes, pratique pour effectuer des benchs sur des scripts (récupérer le temps au début, à la fin et faire une soustraction)

function checkemail($email) {
return eregi('^[_a-z0-9-]+(\.[_a-z0-9-]*)*@[a-z0-9-]+(\.[a-z0-9-]+)+$', $email);
}

Renvoie true si la syntaxe de l'e-mail passé en argument est correcte

A noter aussi que PHP 5 a enfin été released.

Quelques découvertes en vrac, en plus des principales annoncées, concernant l'utilisation de PHP en ligne de commande :

  • Sous win, php.exe a une icône (woawoaw).
  • Il est toujours possible d'exécuter un script localement sans serveur web grâce à la commande php.exe -f script.php (simple rappel car cela est très utile pour ceux qui veulent coder en vitesse des petits outils sans vouloir se plonger dans le C).
  • Par contre php.exe ne dispose plus de l'option -q (Quiet-mode, qui supprime la sortie des headers HTTP, très utile avec l'option -f) car elle est implicite.
  • D'autres options à découvrir (-r, -B, -R, -F, -E, -H) en tapant php -? en ligne de commande.

Il paraît qu'il serait désormais possible de compiler le tout, mais pour l'instant cela dépendrait d'une application payante.

Enfin, la version CGI se nomme php-cgi.exe (auparavant php.exe) et la version CLI se trouve dans le répertoire racine (avant cli/php.exe). Un nouveau mode intéressant a également été introduit : php-win.exe. Qui est une CLI mais qui n'ouvre pas de console (comme php-gtk).

Voir aussi les nouvelles fonctions introduites.

HTTP User-Agent 007

Lundi 12 juillet 2004 | PHP & MySQL
HTTP GET User-Agent

Un petit trou de mémoire dans la liste des user-agents à reconnaître pour établir les statistiques d'un site ? Essayez List of User-Agents (Spiders, Robots, Browsers) - attention 3 pages. Il y a de quoi faire.

Pour rappel, l'user-agent est la ligne envoyée lors d'une requête HTTP par le navigateur vers un serveur web, permettant de l'identifier vis-à-vis de celui-ci. Du style :

GET /chemin/fichier.html HTTP/1.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040206 Firefox/0.9.2

Ce renseignement peut facilement se retrouver dans un script PHP grâce à la variable $HTTP_USER_AGENT, ou de préférence $_SERVER["HTTP_USER_AGENT"] si l'option register_globals est à Off comme il est recommandé. Il ne reste plus qu'à disséquer la chaîne à l'aide de regexp bien épicées.

Pour ceux qui s'intéresseraient de plus près aux échanges HTTP entre un serveur et un navigateur, l'excellente extension WebDeveloper pour Firefox propose via le menu Information > View Response Headers d'afficher les réponses HTTP ayant eu lieu. Sinon il reste toujours la RFC HTTP 1.1 bien consistante.

Générer des fichiers Excel (XLS) avec PHP

Jeudi 1 avril 2004 | PHP & MySQL
Moulinex

Que ce soit pour extraire des informations d'une base de données (ex: MySQL) ou pour les convertir à partir d'un autre format, l'écriture de multiples fichiers Excel par un script de manière automatisée peut s'avérer utile, voire indispensable lorsqu'on vous demande plusieurs centaines de fichiers.

Pour ceci, PHPIndex a publié un mini article PHP et Excel : point de situation, qui date un peu certes mais qui faute de mieux présente des solutions manipulation de fichiers Excel depuis PHP.

Après tri selon les critères les plus courants (générer des fichiers binaires véritablement au format Excel natif, utiliser une librairie facile à installer), PHP_Writeexcel se démarque du lot. A l'aide de deux includes, la création de l'objet writeexcel_workbook (classeur) est à votre portée, ainsi que l'ajout de worksheet (feuilles) à ce classeur. Les cellules sont remplissables par ce type d'instruction : $worksheet->write(x, y, $valeur, $format); où x et y représentent les coordonnées de la cellule dans la feuille de calcul, $valeur le contenu texte de la cellule et $format le format de la cellule.

Il ne faut pas s'attendre à pouvoir définir des formats exceptionnels mais ils sont suffisants dans la plupart des cas. Couleur de fond, police, bordures, alignement du texte, etc. Il est aussi possible de définir la hauteur des lignes ou la largeur des colonnes, voire de fusionner plusieurs cellules entre elles. Les exemples fournis sont un bon point de départ, même si on peut regretter une documentation absente.

La moulinette est performante et ne peut que faire gagner du temps. Il suffit d'envoyer un petit header("Content-Type: application/x-msexcel"); pour obliger le navigateur à considérer le fichier dans le bon type (affichage ou téléchargement), ou bien de demander au script de l'écrire sur le disque. Après test en situation réelle, une centaine de classeurs comportant chacun une page basique munie d'un tableau de données de taille 6x40, sont générés en 20 secondes.