Posts tagged “php”.

Google Chart PHP Library 0.4

I released a new version of my PHP library for Google Chart API. Remember it’s still in heavy development (well, depending on my free time and my motivation, so “heavy” is relative), therefore don’t except anything bug-free or feature complete.

Less rigid API

Until this version, I was focusing on implementing strictly the Google Chart API. However, I eventually realize that the API is sometimes too rigid. For example, say you want to hide an axis. You have to specify “_” (underscore) as the 5th value (axis_or_tick) in the chxs parameter (values are separated by a coma). Looks easy right? Except it is NOT ok to omit the first 4th values. So you have to specify the label_color, font_size and alignment before, in order to be able to hide your axis.

In version 0.3, you had to do exactly that, by using setStyle and specifying the 4th parameter ($axis_or_tick). If you wonder why it’s not the 5th, it’s because the “axis index” value is calculated on runtime. Fortunatly, you could pass null as the value for the parameter, and the library will replace them by the default value. Example:

$axis = new GoogleChartAxis('x');
$axis->setStyle(null, null, null, '_');

In version 0.4, the setStyle method as been removed and splitted into multiple methods setLabelColor, setFontSize, setLabelAlignment, setDrawLine, setDrawTickMarks and setTickColor. Now you don’t need to worry about how many parameter you have to set, just call the method you want and the library will take care of setting the appropriate intermediate values. Example:

$axis = new GoogleChartAxis('x');
$axis->setDrawLine(false)->setDrawTickMarks(false);

More abstraction

This version also comes up with a set of features to simplify chart creation. For example, one of my favorite is setBorder method for Shape Markers (GoogleChartShapeMarker).

To create a border in a shape with Google Chart API, you need to create another similar marker below the first one (think z-order), with a different color and a slightly bigger size. Well, this can be done exactly this way in version 0.3. However, starting version 0.4, the setBorder method does the job for you. Just specify a color and the size of the border, and it will create the second marker automatically. Not only this is more convenient and easy to write, but this is also faster and uses less memory.

New features

This version adds support for Dynamic Icon. Because icons can be either “freestanding” (used as a chart) or used as marker, I had to refactor the base class. Now the base class is GoogleChartApi which holds the logic to query the API. GoogleChart and GoogleChartIcon extends this class, so you can use a GoogleChartIcon exactly the same way as a chart.

Example:

require '../lib/icons/GoogleChartIconNote.php';

$chart = new GoogleChartIconNote('Hello world');
$chart->setTitle('Example');
$chart->setTextColor('D01F3C');

header('Content-Type: image/png');
echo $chart;

To use a icon as a marker, use the new addDynamicMarker method. Example:

require '../lib/GoogleChart.php';
require '../lib/icons/GoogleChartIconNote.php';

$values = array();
for ($i = 0; $i <= 10; $i += 1) {
	$values[] = rand(20,80);
}

$chart = new GoogleChart('ls', 500, 200);
$data = new GoogleChartData($values);
$chart->addData($data);

$marker = new GoogleChartIconNote('Hello');
$marker->setData($data);
$chart->addDynamicMarker($marker);

header('Content-Type: image/png');
echo $chart;

For the moment, only “note” icon (aka Fun style notes with text and optional title) are supported, but I’m working on it.

Hey, the project has a new home!

Yes, the project is now hosted by Google Code. Because there is already a shitload of abandonned projects named using every possible combinations of “google” “chart” and “php”, I had to use the (rather long) name “googlechartphplib”. So new home is here:
http://code.google.com/p/googlechartphplib. You’ll find source code, issue tracker, documentation and the new SVN access there.

Announcing GoogleChart PHP library 0.3

I’ve been playing around a lot with Google Chart API lately, mainly for fun to draw some charts based on my Last.fm profile (Last.fm provides a very nice API). Google Chart API is very powerful, but quite harsh to work with, and unfortunately I didn’t find any good and easy-to-use PHP library for it. There are some but most of them are either not maintened or not fully working. So I ended up writting my own library. A few weeks ago, I used it for a project at work, improved it a bit and it worked like a charm. Eventually I decided to release it open-source (MIT license). It’s provided “as is”, without warranty of any kind. I just hope that it might be useful to somebody else as well, who knows?

Quick introduction

The library’s goal is to provide an easy way to build requests to Google Chart API, and especially to ease the painfull strings concatenation with comas, pipes, colons, etc. If you’ve already tried Google Chart API, you know what I mean! :-) So I wrote a couple of class, that allows to quickly create a chart (GoogleChart), add data series (GoogleChartData), axes (GoogleChartAxis) and markers (GoogleChartMarker), and compute an URL (for GET requests) or an array of parameters (for POST requests). It can even fetch the image for you (via GET or POST) so that you can display it directly (or cache it, or do whatever you want with it).

More… »

Logs PHP avec syslog

Pendant longtemps j’ai cherché comment uniformiser les logs de mes applications PHP, et plus particulièrement des nombreux scripts en ligne de commande qui s’exécutent régulièrement (oui, je suis un grand fan de PHP en ligne de commande) et des applis web quand elles génèrent une erreur. Pour aller droit au but : j’ai trouvé (mais ça, vous vous en doutiez) et maintenant j’utilise du syslog partout. Mais patience, je vais y venir.

D’abord qu’est-ce que j’entends par “logs” ? Il y a bien sûr tous les messages d’erreurs, que ce soit des erreurs générées par PHP (genre “la base de données ne répond plus”) ou des erreurs générées manuellement (genre “c’est quoi ce bordel je devrais jamais tomber dans ce cas là”). Mais il y a également les messages d’informations sur l’état d’avancement du script en ligne de commande (que personne ne lit mais qui pourront peut-être être utile le jour où le script va faire n’importe quoi) ou encore les messages de debug (pratique pour le développement). Pour les applications web, toutes les erreurs génèrent un code HTTP 500 et une page d’erreur propre pour le client, mais j’aimerais bien pouvoir garder une trace de ce qui a foiré.

Pour un script en ligne de commande

Pour cette partie je vais essayer de détailler le plus possible, mais il vaut mieux être familier avec les systèmes Unix, car cela concerne exclusivement des scripts qui sont exécutés avec la SAPI CLI (plus d’infos dans la doc de PHP).

Affichage standard

Au départ, reflexe de programmeur PHP, j’utilisais simplement les fonctions echo (ou printf), mais ça devient vite un casse-tête de filtrer les messages selon leur niveau d’importance. Et quand le script n’est pas lancé en ligne de commande (par exemple s’il est lancé via une cron), ces messages ne sont plus visibles. Il est cependant possible de les archiver en redirigeant le flux de sortie standard vers un fichier. Mais il faut penser faire la rotation de ce fichier de log manuellement (voir logrotate) et on se retrouve vite avec une multitude de fichiers de log éparpillés sur le disque, ce qui ne facilite pas la maintenance.

Exemple, pouet.php contient :

echo "pouet\n";

On redirige le flux :

$ php pouet.php > /tmp/pouet

More… »

Internationalisation d’une base de données

Disons que vous soyez en charge d’une application web écrite en PHP/MySQL, par exemple l’intranet de votre entreprise, et que vous ayez soudainement besoin de l’internationaliser parce que votre entreprise installe des bureaux à l’étranger et que, malheureusement, notre merveilleuse langue française n’est pas parlée dans tous les pays du monde.

Pour les templates, pas de problème, gettext est là pour ça (je reviendrais peut-être dessus dans un futur article, si je suis motivé). Si vous n’avez pas envie de mettre les mains dans le système, votre framework propose sûrement une émulation plus ou moins performante en pur PHP, ou, au pire, une solution “maison”. Bref, ça c’est facile.

Ce qui pose plus de problèmes, ce sont les données présentes en base. Par exemple : la liste de catégories pour les tickets d’incidents des clients. Elle est stockée en base dans une table qui contient notamment l’intitulé de cette catégorie. Oui, mais cet intitulé doit être traduit. Et comme les catégories sont gérées dynamiquement, ce n’est pas envisage d’utiliser la méthode gettext qui repose sur des fichiers statiques.

Transformer le modèle

Nous allons commencer par ajouter une table pour stocker les traductions. Si on envisage la catégorie comme un élément identifié par un id uniquement, les traductions sont liées à une catégorie par une relation “1-N” : 1 catégorie possède N traductions. Chaque traduction est identifiée par un code de langue. L’idée est de retirer les champs contenant du texte à traduire de la catégorie, et de les stocker dans la table contenant les traductions

Schéma de la base

Schéma de la base

On crée donc les tables suivantes :

CREATE TABLE `category` (
	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
	`created_at` DATETIME NOT NULL,
	`deleted_at` DATETIME NULL,
	PRIMARY KEY (`id`)
) ENGINE = InnoDB;

CREATE TABLE `category_i18n` (
	`category_id` INT UNSIGNED NOT NULL,
	`lang` VARCHAR(6) NOT NULL,
	`name` VARCHAR(45) NOT NULL,
	PRIMARY KEY (`lang`, `category_id`),
	INDEX `category_i18n_category_fk` (`category_id` ASC),
	CONSTRAINT `category_i18n_category_fk`
		FOREIGN KEY (`category_id` )
		REFERENCES `category` (`id` )
		ON DELETE CASCADE
) ENGINE = InnoDB;

More… »

Développement web collaboratif

On me demande souvent comment j’organise le développement web dans mon entreprise : comment on arrive à coder à plusieurs sur le même fichier sans se marcher sur les pieds, comment on archive les versions, comment on effectue les livraisons en production, etc. Il est vrai que le développement web collaboratif est souvent mal organisé, et il est courant d’avoir comme seul outil un simple dossier partagé…

Contraintes liées au développement web collaboratif

Contrairement à un projet classique qui ne nécessite “que” un compilateur et des bibliothèques, une application web est une association complexe de plusieurs composants logiciels dont les versions et les configurations très variables peuvent influer sur le bon fonctionnement de l’application :

  • un serveur web (vhost, htaccess, mod_rewrite, etc.),
  • l’interpréteur php (options de php.ini, modules supplémentaires comme pdo, gettext, etc.),
  • le sgbd (configuration des users, etc.).

Donc la solution “classique” d’avoir un poste de développement par développeur est ici difficile à maintenir : il faudrait installer tous ces logiciels sur chaque poste et surtout veiller à avoir une configuration identique partout. Et ça se complique dès qu’il faut faire une mise à jour de la config…

Une autre solution serait d’avoir un serveur de dev unique (pour éviter les problèmes de maintenance évoqués ci-avant), et de travailler directement dessus via des partages de fichiers (Samba, NFS, etc.). Or cette solution pose plusieurs problèmes :

  • en cas d’accès concurrents à un fichier : le risque est grand de voir ses modifications écrasées par un autre développeur ;
  • en cas de modifications lourdes (exemple : un refactoring de la base) : les autres développeurs sont bloqués ;
  • impossible d’utiliser correctement le svn : il n’y a qu’une seule version des fichiers et on ne sait pas qui l’a modifiée.

Nous avons donc créée une solution intermédiaire : un serveur de dev unique (pour une maintenance facile), qui fournit des serveurs virtuels pour chaque développeur (pour une bonne séparation des données et une utilisation optimale de svn).

Le serveur de dev fonctionne avec Debian GNU/Linux, les postes clients avec Windows XP.

More… »

N’utilisez pas isset pour vérifier l’existence d’une clef !

La bonne blague PHP du jour concerne la fonction isset qui permet, comme son nom l’indique, de tester si une variable est affectée. Si vous êtes comme moi, vous avez pris l’habitude de l’utiliser pour vérifier qu’une certaine clef existe dans un tableau avant d’y accéder, afin d’éviter le traditionnel message “Notice: Undefined index”.

Seulement voila, isset retourne false si la variable contient null… Exemple :

$array = array(
	'toto' => null
);
var_dump(isset($array['toto'])); // boolean false

Résultat : on n’obtient pas du tout le résultat attendu, puisque selon PHP la clef n’est pas définie alors que selon le programmeur (moi, en l’occurence) l’index toto existe bien ! D’après la documentation, il faut donc utiliser array_key_exists pour tester qu’une clef existe…

Bon, que PHP considère qu’une variable définie mais de valeur null et qu’une variable non-définie soit la même chose, c’est déjà un peu curieux, mais là où ça devient complètement ridicule c’est que isset renverra bien true pour une chaine vide (ainsi que pour false), alors que c’est équivalent à null avec l’opérateur de comparaison non-typé == ! Alors pourquoi isset n’a pas le même comportement pour toutes ces valeurs ?

$array = array(
	'toto' => null,
	'tata' => ''
);

var_dump(isset($array['toto'])); // boolean false
var_dump(isset($array['tata'])); // boolean true
var_dump($array['toto'] == $array['tata']); // boolean true

Les fetch modes de PDO 4 : les modes modificateurs

Dernière partie de ma série consacrée aux modes de récupération de PDO, voici les modes que j’appelle “modificateurs”, car ils ne peuvent pas être utilisés tout seuls et se contentent de modifier le comportement d’un autre mode.

Pour utiliser un modificateur, il suffit d’effectuer un “ou” binaire, par exemple :

$results->fetchAll(PDO::FETCH_TRUC | PDO::FETCH_BIDULE | PDO::FETCH_CHOUETTE);

La plupart de ces modes ne fonctionnent pas lorsqu’ils sont définis par la méthode setFetchMode. Ça ressemble a un bug, mais vu que rien n’est documenté, c’est peut-être normal…

More… »

Les fetch modes de PDO 3 : les modes spéciaux

Suite de ma série consacrée aux modes de récupération de PDO, voici les modes “spéciaux”, c’est à dire des modes au comportement particulier, très mal documentés mais souvent très pratiques !

More… »

Les fetch modes de PDO 2 : les modes orientés objet

Suite de ma série consacrée aux modes de récupération de PDO, voici les modes qui permettent de travailler avec des objets.

More… »

Les fetch modes de PDO

PDO propose une quantité assez impressionante de “modes de récupération” (fetch mode) des données. Entendez par là qu’il est possible de personnaliser le comportement des méthodes fetch et fetchAll pour obtenir les résultats des requêtes SQL sous des formes très diverses. Si certains modes sont relativement classiques et ont des équivalents avec les précédents drivers MySQL (mysql_fetch_array, mysql_fetch_row, etc.), d’autres sont totalement inédits… mais très mal documentés ! Et pourtant, certains sont *très* pratiques… J’ai donc décidé d’écrire une série d’articles présentant tous les modes de fetch, leur fonctionnement et surtout leurs performances.

More… »