le blog technique de la team weedo
Un nouveau client Weedo, un site en construction :Haymann Editions, maison d'édition de meubles et objets contemporains :)
David Haymann vous invite à découvrir la première collection de sa maison d'édition de meubles et objets contemporains, conçue par le designer Toni Grilo au Salon Maison et Objet du 20 au 24 janvier 2012, Paris Nord Villepinte
Avoir accès à un objet PDO n'est pas suffisant pour être certain d'avoir une connexion à une bdd. Il arrive de passer une requête et d'obtenir l'erreur :
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away' in…
Pour obtenir cette erreur, vous pouvez faire le test suivant :
$pdo = new PDO($dsn, $user, $password); echo get_class ($pdo); // On a bien un objet PDO $pdo->query('select 1'); // ça passe sleep(20); // Vous avez 20 secondes pour killer manuellement la connexion mysql. Faites-le pour les besoins du tests, echo get_class ($pdo); // On a toujours un objet PDO, mais cet objet n'est pas informé que la connexion correspondante a été killée, ce qu'on va voir tout de suite : $pdo->query('select 1'); // !! ça casse : Erreur MySQL server has gone away. Pourtant, on avait bien un objet PDO
Les raisons possibles de cette erreurs sont nombreuses : http://dev.mysql.com/doc/refman/5.0/en/gone-away.html
En plus de/plutôt que/en attendant de résoudre le problème, j'ai trouvé 2 méthodes (assez proche) pour contourner le problème : On tente la connexion avec notre vieille connexion pdo, et si on obtient une erreur, on créé un nouvel objet pdo tout neuf.
Méthode 1
$sql = 'SELECT count(*) FROM `TABLE`;'; for ($i = 1; $i <= 2; $i++) { try { $nb = $pdo->query($sql)->fetchColumn(); if (is_int($nb)) { // C'est bon, ma vieille connexion a fonctionné. break; } } catch (PDOException $e) { //Oups, j'ai une erreur de connexion if ($i == 1) { // C'est la première fois ? OK, je recréé une connexion. $pdo = new PDO($dsn, $user, $password); } else { // C'est la 2eme fois ? OK, c'est mort. $nb = "(nombre inconnu)"; echo 'PDO Connection failed: ' . $e->getMessage().'. '; } } }
Méthode 2
// Je test si ma vieille connexion est OK avec une requête toute simple try { $pdo->query('select 1;') //C'est bon; } catch (PDOException $e) { //Oups, j'ai une erreur de connexion // Je recréé une connexion. $pdo = new PDO($dsn, $user, $password); } // Ici j'ai plus de chance d'avoir un objet pdo viable que si je n'avais pas fait le petit try/catch au-dessus => Je fais ma requête $sql = 'SELECT count(*) FROM `TABLE`;'; $nb = $pdo->query($sql)->fetchColumn();
Comme d'hab, si quelqu'un a mieux, ce que j'espère, je suis preneur !
Après un
header("Location: $url");
Si vous ne voulez pas que la suite du php s'exécute, il faut le préciser, en mettant un exit juste derrière par exemple.
Sinon, le script php continue de s'exécuter et la page est redirigée à la fin de l'exécution du script.
Voici une démo :
// Le fichier toto.txt va être créé et écrit, et ce n'est qu'au bout des 10 sec d'exécution du script que le navigateur va être redirigé. header("Location:http://www.weedo.fr"); $f = fopen('toto.txt', "w"); for ($i = 1; $i <= 10; $i++) { sleep(1); fwrite($f, $i.PHP_EOL); }
Jusqu'à maintenant je pensais que le header+location faisait un exit implicite, ce qui, après réflexion, n'est pas logique.
Je n'ai pas encore testé cette astuce, je l'ai simplement vu sur un serveur (appelons le exemple.com) :
L'admin a mis la règle suivant dans le fichier vhosts.conf (CentOS) :
# more vhosts.conf
RewriteEngine On
RewriteMap lowercase int:tolower
RewriteRule ^/(.*)$ /home/${lowercase:%{SERVER_NAME}}/$1Ainsi, les utilisateurs créent des dossiers .exemple.com dans le dossier home, ce qui créé dynamiquement les sous domaine.
Par exemple, si un utilisateur crée un dossier foo.exemple.com, les fichiers dans le dossier seront disponibles à l'adresse foo.exemple.com
Mis à jour le 12 juillet 2011.
Attention : A utiliser avec précaution.
Combien avez-vous gagné d'espace disque en utilisant ces astuces ?
Partagez vos astuces dans les commentaires !
/* * myFunctionArray function. * Replace 'myFunction' with the name of the function you want to use. Keep the quotes. * @param array $array, collection of elements to pass to the function * @return array of elements which have been processed by the function */ function myFunctionArray(array $array) { return array_map(array($this, 'myFunction'), $array); }
/* * anyFunctionArray function. * Pour une méthode static, remplacer `$this` par `self` * @param string $functionName, Name of the function to call * @param array $array, collection of elements to pass to the function * @return array of elements which have been processed by the function */ function anyFunctionArray($functionName, array $array) { return array_map(array($this, $functionName), $array); }
On peut aussi utiliser une boucle foreach, mais c'est moins élégant.
Je suis tombé sur un bug PDO qui m'a fait perdre beaucoup de temps :
J'avais cette requête :
$query = $pdo->prepare($sql); $result = $query->execute(); if ($result === false) { var_dump($result); echo $pdo->errorCode(); var_dump($pdo->errorInfo()); }
J'obtenais :
(bool)false 00000 Array() /* c'est à dire tableau vide, pas de message d'erreur */
execute() échouait mais sans code ni message d'erreur
J'ai remplacé mon code par :
$result = $pdo->query($sql); if ($result === false) { var_dump($result); echo $pdo->errorCode(); var_dump($pdo->errorInfo()); }
Et là j'ai eu mon message erreur :
(bool)false 00000 [0] => 42S02 [1] => 1146 [2] => Table 'xxxx' doesn't exist
Conclusion, si votre prepare()/execute() ne fonctionne pas sans message d'erreur, remplacez le temporairement par un query() qui sera peut-être plus bavard.
[EDIT] Ce bug est le même que celui décrit ici : https://bugs.php.net/bug.php?id=37285
K.
Lorsque vous utilisez des variables dans des vues html, il faut faire attention aux caractères spéciaux html : quote, double quote, < >, etc., qui pourraient être contenus dans la variable et interférer avec le html
Exemple, cas réel :
a href = '$variable'
avec $variable qui contient COTE D'AZUR… => #fail (cas réel).
Donc, au niveau de la vue :
htmlspecialchars($variable, ENT_COMPAT ,'UTF-8')a href = "$variable" plutôt que a href = '$variable' car les doubles quotes sont moins fréquents dans l'écrit (en français en tout cas). Cela permet aussi d'utiliser htmlspecialchars ou htmlentities avec le deuxième paramètre par défaut.Snippet :
$converted = htmlspecialchars($variable, ENT_COMPAT ,'UTF-8');
link :php.net/htmlspecialchars
K.
I wrote a simpler email validator for Zend. Here it is :
namespace Weedo\Validate; /** * Weedo EmailAddress Validator class. * * @author http://twitter.com/kaweedo */ class EmailAddress extends \Zend_Validate_Abstract { const INVALID = 'emailAddressInvalid'; protected $_messageTemplates = array( self::INVALID => "Email is not valid" ); /** * isValid function. * Defined by Zend_Validate_Interface * * Returns true if and only if $value is a valid email address * according to RFC2822 * * @access public * @link http://php.net/manual/en/function.filter-var.php * @param string $value * @return boolean */ public function isValid($value) { if(filter_var($value, FILTER_VALIDATE_EMAIL) === false) { $this->_error(self::INVALID); return false; } else { // We only check the presence of a dot on the domain part $components = explode("@", $value); $domain = $components[1]; if (strpos($domain, ".") === false) { $this->_error(self::INVALID); return false; } return true; } } }
Usage example :
$emailAddressValidator = new Weedo\Validate\EmailAddress(); /* $emailAddressValidator = new Zend_Validate_EmailAddress(); too complicated */ $this->addElement( 'text', 'email', array( 'placeholder' => ucfirst($this->getTranslator()->translate('Your email'))."*", 'required' => true, 'validators' => array( array('NotEmpty', true, array('messages' => $this->getTranslator()->translate('Email is mandatory'))), array($emailAddressValidator,true), ), ) );
source :
http://www.electrictoolbox.com/php-email-validation-filter-var/
http://php.net/manual/en/function.filter-var.php