Symfony2: nom de la route depuis un template Twig

Dans Symfony2, il est possible d’accéder aux propriétés de la requête actuelle à partir d’un template Twig grâce aux variables globales.

En l’occurrence, ça peut être utile pour connaître le nom de la route utilisée. Ainsi, avec la variable app.request, on peut avoir accès aux attributes, et donc à la route utilisée. En PHP, on aurions pu récupérer l’information comme ceci:

$request->attributes->get('_route');

Avec Twig, le code deviens ceci:

{{ app.request.attributes.get('_route') }}

Une fonctionnalité toute bête mais qui peut s’avérer très pratique!

Symfony 2 et PostgreSQL: Mots réservés

Symfony 2 propose une abstraction des entities très intéressante grâce à Doctrine. Je poste ce petit article car j’ai eu une erreur tout simple:

 $ php app/console doctrine:schema:update --force
Updating database schema...
 
[PDOException] SQLSTATE[42601]: Syntax error: 7 ERREUR:  erreur de syntaxe sur ou près de « User » 
LINE 1: CREATE TABLE User (id INT NOT NULL, username VARCHAR(255) NO...              
                       ^          

En fait, j’ai créé un bundle nommé User, et doctrine souhaite donc créer la table User. Le problème, c’est que user est un mot clé réservé dans PostgreSQL. Par conséquent, il faut donc forcer Doctrine à escaper le nom de la table. Pour se faire, il suffit d’ajouter une annotation Table en préfixant et suffixant le nom de la table par `.

Voici par exemple ma classe User avant la correction:

/**
 * @ORM\Entity
 */
class User extends BaseUser
{
    // ...
}

Il suffit donc de d’ajouter l’annotation @ORM\Table en spécifiant le nom de la table entouré de `. Le nouveau code est:

/**
 * @ORM\Entity
 * @ORM\Table(name="`User`")
 */
class User extends BaseUser
{
    // ...
}

Ainsi, Doctrine va générer ses requêtes en ajoutant des caractères d’échappement sur le nom de la table. Ainsi, vous n’aurez plus d’erreur! :)

Polygones de Thyssen: algorithme de Steven Forture en PHP

Pour des besoins professionnels, j’ai réécrit l’algorithme de Steven Fortune permettant d’obtenir un diagramme de Voronoï à partir de points connus, en transformant la librairie JavaScript de gorhill.

Vous pouvez trouver les fichiers sources (en PHP 5) sur ce dépôt GitHub:

Exemple d’utilisation

Voici un exemple d’utilisation, qui permet de générer un diagramme de Voronoï (ou autrement dit des polygones de Thyssen) à partir de points générés automatiquement:

<?php 
require_once '../library/Nurbs/Voronoi.php';
require_once '../library/Nurbs/Point.php';
 
$bbox = new stdClass();
$bbox->xl = 0;
$bbox->xr = 400;
$bbox->yt = 0;
$bbox->yb = 400;
 
$xo = 0;
$dx = $width = 400;
$yo = 0;
$dy = $height = 400;
$n = 20;
$sites = array();
 
// On créé l'image
$im = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($im, 255, 255, 255);
$red = imagecolorallocate($im, 255, 0, 0);
$green = imagecolorallocate($im, 0, 100, 0);
$black = imagecolorallocate($im, 0, 0, 0);
imagefill($im, 0, 0, $white);
//imageantialias($im, true);
 
// On créé des points aléatoires que l'on dessine
for ($i=0; $i < $n; $i++) {
	$point = new Nurbs_Point(rand($xo, $dx), rand($yo, $dy));
	$sites[] = $point;
 
	imagerectangle($im, $point->x - 2, $point->y - 2, $point->x + 2, $point->y + 2, $black);
}
 
$voronoi = new Voronoi();
$diagram = $voronoi->compute($sites, $bbox);
//var_dump($diagram);
 
//var_dump('sites', $sites, 'diagram', $diagram, 'cells', $diagram['cells']);//, 'voronoi', $voronoi);
$j = 0;
foreach ($diagram['cells'] as $cell) {
	// On va agreger les points du polygone.
	$points = array();
 
	if (count($cell->_halfedges) > 0) {
		$v = $cell->_halfedges[0]->getStartPoint();
		if ($v) {
			$points[] = $v->x;
			$points[] = $v->y;
		} else {
			var_dump($j.': no start point');
		}
 
		for ($i = 0; $i < count($cell->_halfedges); $i++) {
			$halfedge = $cell->_halfedges[$i];
			$edge = $halfedge->edge;
 
			if ($edge->va && $edge->vb) {
				imageline($im, $edge->va->x, $edge->va->y, $edge->vb->x, $edge->vb->y, $red);
			}
 
			$v = $halfedge->getEndPoint();
			if ($v) {
				$points[] = $v->x;
				$points[] = $v->y;
			} else {
				var_dump($j.': no end point #'.$i);
			}
		}
	}
 
	// On construit le polygone
	$color = imagecolorallocatealpha($im, rand(0, 255), rand(0, 255), rand(0, 255), 50);
	imagefilledpolygon($im, $points, count($points) / 2, $color);
	$j++;
}
 
// On affiche l'image
imagepng($im, 'voronoi.png');

Voici un exemple d’image:

Zend PHP 5.3 Developer Certified

Ça y est, je suis développeur PHP 5.3 certifié par Zend! :-)

Le principe du concours est très simple: vous avez 90 minutes pour répondre à 70 questions aléatoires concernant le fonctionnement de PHP ainsi que les différents domaines qui l’entour, à savoir le SQL, la sécurité en général, etc…

Je vous conseil de le passer, c’est sans aucun doutes un bon élément sur le CV. Si vous avez un quelconque question, n’hésitez pas!

Un rapport par défaut dans Trac

Dans Trac, lorsque l’on clique sur “Voir les tickets”, on arrive sur la liste des différents rapports disponibles.

Pour des questions pratiques, je préférais arriver directement sur la page du rapport des tickets actifs. On peut donc modifier les liens du menu horizontal pour y arriver! Modifiez donc le fichier trac.ini comme ceci:

[mainnav]
tickets.href = /report/1

Ainsi, ce sera le rapport d’ID 1 qui sera ouvert.

Crypter un mot de passe comme dans /etc/shadow

Petit test pour crypter un mot de passe comme dans le fichier /etc/shadow avec Python! Vous pouvez crypter une chaîne de caractères en utilisant le même SALT, à savoir la clé de cryptage.

Dans une chaine du fichier /etc/shadow, voici un exemple de ligne:

sroze:$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50:15224:0:99999:7:::

Ici, on peut voir que mon mot de passe personnel est $6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50. Cette chaine signifie que l’encodage utilisé est le numéro 6 ($6$) à savoir le SHA-2, le SALT est jWp7fotG. Vous pouvez retrouver plus d’informations à ce sujet ici.

En utilisant la même clé, on peut donc retrouver le mot de passe, comme ceci!

# python -c "import crypt, getpass, pwd; print crypt.crypt('-PASSWORD-', '\$6\$jWp7fotG\$')"
$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50

On vérifie la correspondance:

# cat /etc/shadow | grep sroze | cut -d":" -f2
$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50

:-)

C: Régler le problème des defunct process

Lorsque vous développez une application, il est parfois très intéressant d’utiliser des threads ou plusieurs processus pour exécuter plusieurs tâches simultanément. Nous allons ici voir un problème qui arrive lors que l’on utilise plusieurs processus, via un fork(). En effet, en C, la fonction fork permet de créer un nouveau processus, qui devient fils du processus appelant le fork.

Processus zombies (defunct)

Par défaut, lorsque le processus père s’arrête, tous les processus fils s’arrête. À l’inverse, lorsqu’un processus fils s’arrête – via un exit(0); par exemple -, sa mémoire est libérée, il devient un processus zombie (seul le bloc de contrôle reste présent) et le processus père continue de fonctionner.

Ainsi, l’on peut voir de nombreuses lignes marquées par un defunct lorsque l’on liste les processus avec un ps:

root      9175  0.0  0.0 136380  1100 ?        Sl   Jun30   0:00 /[...]/relay
root      9629  0.0  0.0      0     0 ?        Z    Jun23   0:00 [relay] <defunct>
root      9853  0.0  0.0      0     0 ?        Z    Jun30   0:00 [relay] <defunct>
root      9884  0.0  0.0      0     0 ?        Z    Jun30   0:00 [relay] <defunct>

C’est parce que le processus père n’écoutes pas le signal SIGCHLD, qui est envoyé par le fils lors de son extinction. Ainsi, en écoutant le signal, le père peut libérer son bloc de contrôle. En C, c’est la fonction waitpid qui nous sera utile.

Une ligne à ajouter

Il n’y a qu’une seule ligne (ainsi qu’un #include) à ajouter à votre code C pour que les processus zombies soient “ramassés” par votre processus père. De temps en temps – l’idéal étant la boucle principale s’il y a -, exécutée cette ligne ci:

while (waitpid(WAIT_ANY, NULL, WNOHANG) != 0);

Les arguments sont les suivants:

  • WAIT_ANY est la constante permettant de dire que l’on souhaite attendre n’importe quel des processus fils de ce processus. À la place, nous aurions pu mettre le pid d’un processus particulier.
  • NULL permet de ne pas récupérer d’informations de statut du processus.
  • WNOHANG est une option permettant d’exécuter waitpid en mode non-bloquant.

N’oubliez pas d’inclure l’en-tête des fonctions et constantes ainsi:

#include <sys/wait.h>

Ainsi, il ne restera plus de processus zombie, ou defunct.

Varnish en reverse-proxy: le problème des adresses locales

Si vous utilisez nginx ou Apache derrière Varnish, vous aurez remarqué que l’adresse IP du client récupérée est l’adresse locale (ou bien l’adresse du serveur hébergeant Varnish). Cela est le cas parce-que c’est Varnish qui créé la connexion TCP à nginx/apache, et non le client directement. Pour cela, nous allons tout simplement installer un module sur votre serveur Web, pour qui va utiliser une en-tête (X-Forwarded-For) pour connaitre l’IP du client.

Pour nginx

Il nous faut nginx compilé avec le module Real-IP (--with-http_realip_module), ce qui est le cas par défaut dans les paquets CentOS et Debian. Dans le fichier de configuration /etc/nginx/nginx.conf, dans la catégorie http {...}, ajoutez ça:

    set_real_ip_from 127.0.0.1;
    real_ip_header X-Forwarded-For;

Redémarrez le serveur nginx, et c’est bon.

Pour Apache

Pour Apache, il faut installer le module RPAF2. Je vous invite à lire l’article très intéressant de wiki.tyk.nu.

Tunnel SSH sur le port 80, utilisant le reverse proxy Varnish

Dans un article précédent, nous avons vu comment créer une connexion SSH à travers un tunnel HTTP, mais le problème est que vous ne pouviez pas utiliser le port 80 si votre serveur hébergeait un serveur HTTP! Nous allons maintenant voir comment mettre en place Varnish, l’un des meilleurs reverse-proxy (qui peut également servir de système de cache), pour utiliser à la fois httptunnel et votre serveur Web.

Mise en place de Varnish

Nous allons commencer par mettre en place Varnish de la façon suivante:

Pour cela, nous allons installer varnish depuis les dépôts. Pour CentOS:

# yum install varnish

Pour commencer, nous allons modifier le fichier de configuration de Varnish, afin de configurer les différents backends. Nous supposer ceci:

  • Votre serveur Web écoute sur le port 8001
  • Le serveur hts écoute sur le port 8002
    Note: vous pourrez modifier la configuration de votre serveur Web à la fin, si vous souhaitez avoir un minimum de downtime.

Continue reading

Piwik: des statistiques Web à la Google Analitycs

Google Analytics est le service gratuit (pour un usage modéré, mais relativement important) de Google permettant d’obtenir des statistiques très complètes sur les visiteurs ainsi que leurs comportements sur vos sites Web. Il peut également être comparé à Xiti, qui était l’un des premiers services gratuits de statistiques. Le principe est très simple: vous collez un bout de code JavaScript qui appelle une page Web sur le serveur de Google, Xiti ou autre suivant le service que vous utilisez. Ensuite, vous pouvez visualiser les statistiques de vos sites depuis une interface fort sympathique.

Google Analytics

Aperçu de Google Analytics

Aperçu de Xiti

 

 

 

 

 

 

 

 

Deux gros problèmes

À mes yeux, il y a deux gros problèmes

  • Le premier, est que toutes vos données sont stockées chez un prestataire qui n’a aucune garantie si vous ne payez pas un “abonnement” à leurs services.
  • Le second et le plus important, c’est que la vitesse de votre site Web dépend de la vitesse de leurs services: les statistiques étant propulsées par un script JavaScript, le navigateur de votre visiteur va attendre que ce script soit chargé avant de continuer à charger le reste de la page et de terminer le rendu. Ainsi, si le script met 100ms à se charger, dans une bonne partie des cas, l’affichage du côté visiteur sera retardé d’environ 100ms, ce qui n’est pas négligeable!

Par conséquent, il peut être très intéressant de trouver une alternative (open-source de préférence) pour stocker et gérer vous même vos statistiques, le plus simplement possible, de préférence. Le projet le plus abouti est Piwik.

Une alternative très intéressante

Piwik est une application open-source développée en PHP qui fourni tout l’arsenal pour obtenir des statistiques aussi intéressantes que Google Analitycs!

Tableau de bord de Piwik

Récapitulatif visites de Piwik

 

Pour installer Piwik, il vous suffit de télécharger le code PHP, de le mettre en place sur votre serveur Web, de suivre le processus d’installation très bien expliqué, et c’est partit!

$ wget http://piwik.org/latest.zip
$ unzip latest.zip
$ cp -R piwik /home/www/your.domain.example.com/htdocs/
$ chgrp -R www /home/www/your.domain.example.com/htdocs/piwik/
$ chmod g+w /home/www/your.domain.example.com/htdocs/piwik/

Note: Vous pouvez également retrouver le processus d’installation plus détaillé sur le site Web de Piwik.

C’est donc tout naturellement que j’ai choisi Piwik pour récupérer des statistiques de mes sites Web.