Outils pour utilisateurs

Outils du site


tips_informatiques:programmation:php:cakephp

Déboguer le SecurityComponent

CakePHP : 1.3.x

Le SecurityComponent est un composant bien utile de CakePHP permettant entre autre de sécuriser des formulaires: utilisé avec le FormHelper, il est responsable entre autre de:

  • ajouter un champ caché servant de ticket de validation lors du POST
  • comparer les champs affichés dans la page et les champs renvoyés en comparant un hash des noms des champs.

En cas d'erreur de ces comparaisons, par défaut le SecurityComponent affiche une page vide avec un code d'erreur HTTP.

Lors du développement, il peut alors être difficile de déterminer pour quelle raison un formulaire se bloque lors de l'envoi. Mais la plupart du temps la raison est que la comparaison des champs affichés par le FormHelper et les champs renvoyés (et donc vérifiés par le SecurityComponent) ne correspondent pas.

Comment comparer les champs affichés par le FormHelper et les champs renvoyés ?

SecurityComponent

Mettre un point d'arrêt de debug à la fin de la méthode _validatePost(&$controller) pour comparer les variables $token et $check

  ...
  $check = Security::hash(serialize($fieldList) . Configure::read('Security.salt'));
  return ($token === $check);
}

Si les valeurs de $token et $check sont différentes, on est bien dans le cas d'une différence entre champs affichés et champs renvoyés

Dans ce cas:

FormHelper

Mettre un point d'arrêt dans la méthode secure($fields = array()). Cette méthode est appelée par la méthode end($options = null) de FormHelper. Ce point d'arrêt permet de déterminer quels sont les champs affichés du formulaire (variable $fields en début de méthode) et le hash qui en découle (variable $fields en fin de méthode).

function secure($fields = array()) {
	if (!isset($this->params['_Token']) || empty($this->params['_Token'])) {
		return;
	}
 
	...
 
	$fields = Security::hash(serialize($fields) . Configure::read('Security.salt'));
 
	...
 
	return $out;
}

Réutiliser le point d'arrêt mis dans SecurityComponent afin de voir le contenu de $fieldList qui devrait être différent du contenu de $fields dans FormHelper.

A partir de là, il ne restera plus qu'à savoir d'où vient cette différence !

Note:

Une erreur courante empêchant le SecurityComponent de fonctionner est le fait de ne pas fermer les formulaires:

La fonction submit($caption = null, $options = array()) du FormHelper ne fait qu'imprimer un bouton submit, mais ne ferme pas le formulaire ! Ce qui signifie un code HTML invalide, et dans le cas présent le fait de ne pas passer par la méthode secure($fields = array()) nécessaire au fonctionnement du SecurityComponent.

Erreurs de validation non-montrées

CakePHP : 1.3.x

Alors que j'utilisais la méthode saveAll() dans un controller, les erreurs de validations des Models n'étaient pas montrées. J'ai cherché pendant un moment ce qu'il se passait dans la méthode elle-même, avant de comprendre que le problème se trouvait plus loin dans le code. Je faisais un nouveau read() depuis le Model principal, ce qui a pour effet de réinitialiser la variables $validationErrors !…

Le code suivant explique ceci:

Ici les erreurs ne sont pas montrées:

if (!empty($this->data)) 
{
  if ($this->User->saveAll($this->data, array('validate'=>'first'))) 
  {
    $this->Session->setFlash('User saved');
  } 
  else 
  {
    $this->Session->setFlash('User not saved.');
  }
}
 
$this->data = $this->User->read(null, $id);

Ici les erreurs sont montrées:

if (!empty($this->data)) 
{
  if ($this->User->saveAll($this->data, array('validate'=>'first'))) 
  {
    $this->Session->setFlash('User saved');
  } 
  else 
  {
    $this->Session->setFlash('User not saved.');
  }
} 
else 
{
    $this->data = $this->User->read(null, $id);
}

Encodage de la base de données

CakePHP : 1.3.x (probablement 1.2.x)

Problème :

En faisant un export depuis une base de données MySQL vers une autre base de données, j'ai réalisé que les textes n'étaient pas encodés correctement dans la première.

Une des conséquences dans mon cas particulier était le fait que lors de l'import dans la seconde base de données, l'ensemble des caractères accentués était affiché dans le mauvais encodage une fois dans les pages web. Normal, puisque le script d'export SQL généré par phpMyAdmin contenait déjà ces caractères mal encodés.

Les deux bases de données contenaient pourtant des champs encodés en utf8_unicode_ci.

Solution :

Le problème ne venait pas de l'encodage des champs dans MySQL, mais de la communication entre CakePHP et MySQL qui se faisait dans le mauvais encodage.

Mais il est possible de spécifier au driver MySQL l'encodage à utiliser dans le fichier de configuration de base de données de CakePHP:

class DATABASE_CONFIG {
 
	var $default = array(
		'driver' => 'mysql',
	        'encoding' => 'utf8',  //-> here the encoding is forced
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'my_login',
		'password' => 'my_password',
		'database' => 'my_database',
		'prefix' => 'db_',
	);
}

Remarque :

Dans le cas où vous avez déjà des caractères mal encodés dans votre base de données, le script suivant peut vous permettre de remplacer ces caractères afin de pouvoir néanmoins utiliser le script SQL obtenu lors de l'export: Remplacer des caractères UTF-8 affichés en ISO-8859-1 dans un fichier

Bake des vues avec les vues hors CRUD

Problème:

Un bake lancé avec un simple

$ cake bake

ne génère que les actions du CRUD.

Solution:

Lancer la commande de la façon suivante:

$ cake bake view all

De cette manière, bake recherche les templates pour toutes les actions présentes dans les contrôleurs, ce qui est en plus bien plus rapide pour générer toutes les vues :-)

Cake 2:

/path/to/project/app$ ../lib/Cake/Console/cake bake view Format admin_copy

Bake rapide d'un contrôleur avec actions publiques et admin

Commande:

Lancer la commande de la façon suivante:

$ cake bake controller Comment public admin

find avec conditions sur un modèle obtenu par contain

Code:

$this->Structure->contain(array('Document' => array('fields'            => array('id', 'pid', 'title', 'year'),
                                                    'conditions'        => array('year' => $years),
                                                    'DocumentSubtype'   => array('id', 'name',
                                                                                 'DocumentType' => array('id', 'name')),
                                                    'PublicationVector' => array('id', 'name'),
                                                    'Author'            => array('id', 'firstname', 'lastname', 'cn_individu'))
	                        )
	                   );
tips_informatiques/programmation/php/cakephp.txt · Dernière modification: 2012/02/07 14:36 (modification externe)