PHP Peuch-peuch Cinq Cinq, pour PHP 5.5

Posté par (page perso) . Édité par Nÿco, ZeroHeure, Xavier Claude et Benoît Sibaud. Modéré par Nÿco. Licence CC by-sa
Tags :
37
30
juin
2013
PHP

PHP 5.5 est sorti le 20 juin, un peu plus de 1 an après la version 5.4 (1er mai 2012)

PHP

Sommaire

Nouveautés de PHP 5.5

Générateurs et coroutines

Le support des générateurs a été ajouté via la directive yield, que l'on peut retrouver par exemple, en C#.

Un générateur est une fonction permettant de générer des éléments, comme le fait la fonction range.

Dans l'exemple ci-dessous, on crée un générateur de suite fibonacci pour permettre d'itérer dessus :

function fibonacci($limit = 50) {
   $cur = 1;
   $last = 0;
   for ($i=1;$i<$limit;$i++) {
      yield $cur;

      $tmp = $last;
      $last = $cur;
      $cur = $last + $tmp;
   }
}

echo "Suite de Fibonacci: ";
foreach (fibonacci(10) as $nb) {
    echo $nb." ";
}
echo "\n";

Ce qui nous donnera :

Suite de Fibonacci: 1 2 3 5 8 13 21 34 55 89

Mot-clef finally

Avant la version 5.5 la gestion des exceptions PHP était effectuée par le biais des opérateurs try et catch. L'opérateur catch était appelé lorsqu'une exception était levée par l'appel de la fonction throw.

Le mot-clef finally a été introduit, permettant de combler un manque dans PHP par rapport à d'autres langages comme Java ou Python. finally permet d'ajouter un bloc de code à exécuter, même si une exception a été levée.

Exemple :

$con = NULL;
try {
   $con = mysql_connect("localhost","myuser","mypwd");
   if (!$con) {
      throw new Exception("Echec de connexion à la base de données");
   }
catch {
   echo 'Erreur MySQL : ',  $e->getMessage(), "\n";
}
finally {
   if ($con !== NULL) {
      close($con);
   }
}

API simplifiée pour hasher des mots de passe

Cette nouvelle API permet de hasher rapidement des mots de passe, visualiser quelques infos sur le hash et vérifier leur validité. À l'heure actuelle, seul blowfish est supporté.

Hashage

La fonction password_hash permet d'effectuer ce hashage.

string password_hash ( string $password , integer $algo [, array $options ] )

Les paramètres passés sont :

  • le mot de passe en clair;
  • l'algorithme de hash: PASSWORD_DEFAULT et PASSWORD_BCRYPT - à noter que PASSWORD_DEFAULT correspond pour l'heure à PASSWORD_BCRYPT;
  • des options:
    • salt : un grain de sel afin de complexifier le hash
    • cost : le coût du hash. Plus la valeur est élevée plus le hash est robuste et long à générer.
$options = [
    'salt' => "free-software",
    'cost' => 18,
];
echo password_hash("linuxfr", PASSWORD_DEFAULT, $options);

Comparaison du hash et du mot de passe

La fonction password_verify permet de comparer un mot de passe à un hash défini (par exemple en base de données)

boolean password_verify ( string $password , string $hash )

Vérification de l'algorithme de hash

La fonction password_needs_rehash permet de vérifier que le hash donné correspond bien à l'algorithme et aux critères de complexité donnés.

boolean password_needs_rehash ( string $hash , string $algo [, string $options ] )

Informations sur un hash

Enfin, la fonction password_get_info permet d'obtenir les informations sur un hash (algorithme, options).

array password_get_info ( string $hash )

La fonction retourne un tableau contenant 3 éléments :

  • algo : l'algorithme au format constante
  • algoName : le nom de l'algorithme sous forme lisible
  • options : les options passées lors du hashage du mot de passe (coût et grain de sel)

Déréférencement des tableaux/chaînes de caractères constants

Il est désormais possible d'accéder à des éléments atomiques dans un tableau ou une chaîne de caractères.

echo "linuxfr"[3]."\n";
echo ["bsd","linux","unix"][1]."\n";

retournera :

u
linux

Résolution de nom de classe scalaire

Cette nouvelle notion permet de retrouver le nom d'une classe.

class MyClass1 {}
echo "Le nom de ma classe est: ".MyClass1::class."\n";

retournera :

Le nom de ma classe est: MyClass1

Si vous utilisez les espaces de noms, la fonction affichera également l'espace de noms associé.

namespace MyNameSpace;
class MyClass1 {}
echo "Le nom de ma classe est: ".MyClass1::class."\n";

retournera :

Le nom de ma classe est: MyNameSpace\MyClass1

empty() sur les appels de fonctions et expressions

Auparavant empty ne pouvait être utilisé que sur des variables PHP. Il est désormais possible de l'utiliser sur des appels de fonctions et expressions.

# PHP 5.4
$var = myFunc();
if (empty($var)) {
    // quelque chose
}

$var2 = false;
if (empty($var2)) {
   // quelque chose d'autre
}
# PHP 5.5
if (empty(myFunc())) {
   // quelque chose
}

if (empty(false)) {
   // quelque chose d'autre
}

Clefs d'itération non-scalaires

Added support for non-scalar Iterator keys in foreach.

Utilisation de list() dans les déclarations foreach

Il est désormais possible d'appeler la fonction list dans un foreach:

$array = [
["MySQL", "beaucoup utilisé"],
["PostgreSQL", "monte"],
["Oracle", "trop cher"] ];

foreach($array as list($name,$adj)) {
   echo $name." est ".$adj."\n";
}

retournera :

MySQL est beaucoup utilisé
PostgreSQL est monte
Oracle est trop cher

Extension Zend OPcache

Cette nouvelle extension est dédiée à l'amélioration des performances de PHP. Elle permet de stocker le bytecode généré par PHP dans la mémoire partagée, évitant ainsi de relire et parser les scripts à chaque exécution.

Mise à jour de la bibliothèque GD

GD passe en version 2.1 et intègre des améliorations de fonctions existantes et des correctifs.

De nouvelles fonctionnalités intéressantes ont également été ajoutées :

  • retournement d'images via la fonction imageflip;
  • recadrage avancé via les fonctions imagecrop et imagecropauto.
  • lecture et écriture du format d'images WebP via imagecreatefromwebp et imagewebp.

Mises à jour de compatibilité

  • les GUID du logo PHP ont été supprimés;
  • Windows XP et Windows Server 2003 ne sont plus supportés ( ouf );
  • la sensibilité à la casse n'est plus locale. L'insensibilité à la casse des nom des fonctions, classes et constantes est gérée localement et de manière indépendante, conformément aux règles ASCII.
  • # finally

    Posté par . Évalué à  6 .

    Le mot-clef finally a été introduit, permettant de combler un manque dans PHP par rapport à d'autres langages comme C++, Java ou Python.

    "finally" n'existe pas en C++, et il n'y en a pas besoin, vive RAII :)
    En revanche il me semble que Microsoft l'a rajouté dans son C++ version .NET…

    • [^] # Re: finally

      Posté par (page perso) . Évalué à  2 .

      Effectivement, il s'agit d'une erreur de ma part. Si un modérateur peut corriger

      CNRS & UNIX-Experience

    • [^] # Re: finally

      Posté par (page perso) . Évalué à  1 .

      Quel est le rapport avec RAII ? Même si cette technique permet de libérer une ressource qu'on a oublié de libérer, il est toujours de bon ton de libérer la ressource après usage. Histoire qu'une exception lancée à la libération de la ressource ne vienne pas tout casser dans le destructeur appelant, par exemple.

      • [^] # Re: finally

        Posté par . Évalué à  7 .

        • [^] # Re: finally

          Posté par (page perso) . Évalué à  -2 .

          Et je te renverrai au « Exceptional C++ » de Herb Sutter, qui conseille fortement de libérer une ressource avant de sortir du scope.

          {
            auto f = my_ns::file(".");
            // Do stuff that can raise exception
            f.close();
          }

          Évidement, la ressource devrait être correctement libérée en cas d'exception, mais dans le cas où aucune exception n'est levée, il est tout indiqué de libérer la ressource inutile, pour éviter qu'une exception ne soit lever dans un destructeur.

          • [^] # Re: finally

            Posté par . Évalué à  1 . Dernière modification : le 01/07/13 à 20:21

            Et je te renverrai au « Exceptional C++ » de Herb Sutter, qui conseille fortement de libérer une ressource avant de sortir du scope.

            Je n'ai pas ce livre, donc si tu pouvais étayer un peu ton propos histoire que je comprenne où tu veux en venir…

            Évidement, la ressource devrait être correctement libérée en cas d'exception, mais dans le cas où aucune exception n'est levée il est tout indiqué de libérer la ressource inutile, pour éviter qu'une exception ne soit lever dans un destructeur.

            Je ne vois pas ce que les destructeurs viennent faire dans l'histoire, et encore moins d'où sortirais la fameuse exception qu'il leverait…
            Sans le f.close(), la ressource est correctement libérée, qu'il y ait une exception ou pas, puisque le destructeur va s'en charger.

            • [^] # Re: finally

              Posté par (page perso) . Évalué à  2 . Dernière modification : le 03/07/13 à 12:00

              Prenons un exemple. Imaginons une classe qui prend en charge l'ouverture d'un fichier, et la gestion de son buffer. L'ouverture du fichier est fainéante, l'écriture aussi, et la fonction close lance l'écriture du buffer en dernier ressort. Une exception io_error est lancée lorsqu'une erreur d'écriture est détectée :

              // c++ -o throwing_close{,.cpp} --std=c++11
              #include <iostream>
              #include <string>
              
              
              namespace my_ns
              {
                  class io_error
                  {
                  } /* class io_error */;
              
                  class file
                  {
                      public:
                          // Lazy opener
                          static
                          file const open(std::string const );
              
                          void flush()
                          {
                              throw io_error();
                          }
              
                          void close()
                          {
                              flush();
                          }
              
                          ~file() /* file is not declared nothrow, no warranty on exception safety */
                          {
                              flush();
                              close();
                          }
              
                          // Append content. Open in append mode if file isn't open yet
                          void append(std::string const )
                          {
                          }
              
                  } /* class file */;
              
                  file const file::open(std::string const )
                  {
                      file new_file {};
                      return new_file;
                  }
              
              } // namespace my_ns
              
              int main()
              {
                  std::string content {"Big content that's going to overflow the harddrive"};
              
                  {
                      auto f = my_ns::file::open("throwing_close");
                      f.append(content);
              
                      try
                      {
                          f.flush();
                          f.close();
                      }
                      catch(my_ns::io_error const & e)
                      {
                          std::cout << "Catched exception!\n";
                      }
                  }
              
                  try
                  {
                      auto f = my_ns::file::open("throwing_close");
                      f.append(content);
              
                      // Destructor called: an exception is thrown from dtor
                  }
                  catch(my_ns::io_error const & e)
                  {
                      std::cout << "That can't be catched\n";
                  }
              }

              Le résultat sur la ligne de commande :

              mickael@laptop:~/tmp$ ./throwing_close
              Catched exception!
              terminate called after throwing an instance of 'my_ns::io_error'
              Abandon

              Alors, évidement, ici la classe est facile à repenser, si toutefois elle faisait quelque chose. Mais imagine une architecture plus complexe, où l'exception safety n'est jamais garantie, où aucune signature n'indique qu'une fonction peut lancer une exception, où la libération d'une ressource peut être complexe et entraîner moult lancement d'exception.

              Oui, il faut libérer les ressources dès qu'on le peut, ou des comportement indéfinis sont garantis (ici on notera que l'implémentation tue directement le processus qui aura tenté de lancer une exception depuis un destructeur, il n'est pas possible d'empêcher sa destruction).

              Donc non, même en utilisant un objet RAII, il n'y a pas de garantie à ce que la ressource soit libérée si une exception peut être levée lors de l'exécution d'un destructeur.

              • [^] # Re: finally

                Posté par . Évalué à  1 .

                Ton destructeur balance une exception, évidemment que ça se passe mal, il ne faut jamais lancer d'exceptions dans un destructeur.
                Si tu veux vraiment laisser le fonctionnement de ta classe tel quel (c'est-à-dire écriture fainéante), tu dois par exemple attraper l'exception de flush dans ton destructeur :

                        ~file()
                        {
                            try {
                                flush();
                                close();
                            } catch(my_ns::io_error const & e) {
                                std::cerr << "destruction failure!\n";
                            }
                        }
                

                http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

                Le problème c'est pas RAII, c'est que tu lances une exception dans le destructeur…

                • [^] # Re: finally

                  Posté par . Évalué à  1 .

                  Ton destructeur balance une exception, évidemment que ça se passe mal, il ne faut jamais lancer d'exceptions dans un destructeur.

                  Oui c'est vachement mieux de jeter ca sous le tapis ni vu ni connu ;)

                  Pourquoi tu flush ton flux tout le monde s'en fou quand ca s'est mal passé ? Autant ne pas le faire.

                  Dans les fait j'ai un énorme doute sur le fait que tu puisses toujours gérer correctement une erreur au niveau du destructeur. C'est assez fréquent qu'il faille remonter de X niveau business pour faire ce qu'il y a faire. En général en bas niveau on peut juste remonter que ca à foiré mais l'error recovery est bien plus haut.

                  Je ne fais pas de C++ mais j'ai du mal à voir en quoi ca serait spécifique sur ce point.

                  • [^] # Re: finally

                    Posté par . Évalué à  1 . Dernière modification : le 03/07/13 à 20:20

                    Oui c'est vachement mieux de jeter ca sous le tapis ni vu ni connu ;)

                    J'ai pas non plus dit de jeter ça sous le tapis… Mon exemple affiche un message d'erreur. On peut aussi écrire un truc dans un fichier de log, envoyer un mail à la supervision, appeler std::terminate soi-même, etc. Il y a de nombreuses solutions, mais aucune n'est vraiment satisfaisante. La meilleure chose, c'est encore de faire en sorte de pas avoir d'erreurs à gérer (ou le moins possible) dans les destructeurs. Donc éviter les traitements trop complexes. Si on a besoin d'en faire, à mon humble avis, c'est qu'on a un problème d'architecture dans le programme…

                    Par exemple si je reprends l'exemple de l'écriture fainéante, on peut faire un singleton (qui a la même durée de vie que le programme) qui s'occupe de gérer tous les fichiers ouverts et de les flusher quand nécessaire. Ou alors (et à mon avis c'est encore le mieux pour cet exemple) on fait pas d'écriture fainéante dans notre programme et on laisse l'ordonnanceur d'entrées/sorties du noyau faire son boulot.
                    Pour être honnête, je trouve ça vraiment gênant cette histoire d'écriture fainéante, puisque quoi qu'il arrive, on ne peut pas remonter les erreurs à l'appelant au bon moment.
                    On peut aussi considérer que ça fait partie de la sémantique de la classe : les écritures peuvent échouer sans pour autant remonter d'erreurs… Auquel cas l'appelant doit en être parfaitement conscient et architecturer son code en conséquence.

                    Ou sinon il faut expliquer à Bjarne Stroustrup que lancer des exceptions dans un destructeur c'est bien et que c'est pas grave de pouvoir se retrouver avec deux exceptions à gérer en même temps ou autre joyeuseté…

                    • [^] # Re: finally

                      Posté par (page perso) . Évalué à  1 .

                      L'écriture fainéante (et tout processus fainéant, comme l'overcommit memory, COW, etc) est toujours difficile à déboguer, puisque c'est un procédé par nature asynchrone. Et ceci me pose autant de problèmes qu'à toi. Malheureusement, les humains n'aiment pas attendre, et parfois il faut abandonner un peu de fiabilité (oui, ça me fait mal de dire ça) pour un peu de confort (rapidité visuelle).

                      Je préfère que le programme plante, histoire de ne pas avoir un état incohérent, et que le couillon qui gère l'administration du produit ne se dise pas que ce n'est qu'un « warning ».

                      Oh oui, mets-moi du singleton là où il n'y en a pas besoin. D'ailleurs, par durée de vie du programme, tu entends une variable statique instanciée lors de la création du process (et donc un comportement indéfini à la clé) ? Oui, le j'ai déclaré le singleton « ennemi public numéro un », puisqu'il est le vengeur masqué de la variable globale.

                      Ici j'ai pris l'exemple d'une classe qui écrit un fichier pour rester simple. Mais on peut imaginer un ORM, qui flush les données modifiées, ajoutées et supprimées vers la base de données. Dans ce cas, le caractère asynchrone de la communication avec un serveur distant est pertinent, et les exceptions peuvent alors être légion.

                      Il semble que tu ne comprennes pas pourquoi lancer une exception depuis un destructeur est problématique. Le problème n'est pas le nombre d'exceptions à gérer, mais le fait que la destruction d'un objet est suspendue par la levée de l'exception, et qu'on se retrouve alors avec un objet partiellement détruit, ce qui pose des problèmes de fiabilité.

                      • [^] # Re: finally

                        Posté par . Évalué à  1 .

                        Je préfère que le programme plante, histoire de ne pas avoir un état incohérent, et que le couillon qui gère l'administration du produit ne se dise pas que ce n'est qu'un « warning ».

                        Donc a priori la solution qui te plairait le mieux ça serait de donner un "handler" (pointeur de fonction ou foncteur) à l'objet, qu'il peut appeler en cas d'erreurs sur une tâche asynchrone (voir mon autre post).

                        D'ailleurs, par durée de vie du programme, tu entends une variable statique instanciée lors de la création du process (et donc un comportement indéfini à la clé) ?

                        Pas nécessairement non.
                        Et d'ailleurs une variable static globale n'est pas un comportement indéfini, il faut juste être très prudent quand on en utilise (j'évite toujours personnellement).

                        Le problème n'est pas le nombre d'exceptions à gérer, mais le fait que la destruction d'un objet est suspendue par la levée de l'exception, et qu'on se retrouve alors avec un objet partiellement détruit, ce qui pose des problèmes de fiabilité.

                        C'est bien pour ça que c'est au destructeur de faire quelque chose d'approprié quand il rencontre un problème, au lieu de lèver une exception / en laisser une se propager à l'appelant.

                        Et du point de vue du fonctionnement du langage, c'est effectivement de se retrouver avec deux exceptions à gérer en même temps qui est problématique.
                        http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html

                        Une autre façon de voir les choses : une fonction doit lever une exception si et seulement si ses post-conditions ne peuvent pas être remplies. L'unique post-condition d'un destructeur est que l'objet n'existe plus en mémoire. Cette post-condition est toujours remplie quoi qu'il arrive. Donc un destructeur ne peut jamais légitimement lever d'exceptions.

                • [^] # Re: finally

                  Posté par (page perso) . Évalué à  2 .

                  Non, l'exception n'est pas lancée dans le destructeur. Elle est lancée indirectement depuis le destructeur. Et c'est bien le point que j'essaye de mettre en exergue, et que tu refuses de voir : le RAII c'est très bien, ça permet de mieux gérer les ressources. Mais ce n'est pas magique. Et donc, il faut toujours penser à libérer les ressources dès qu'on peut.

                  Maintenant, je m'attendais à ce que tu vienne avec une solution qui est encore pire qu'un segfault : attraper l'exception dans le destructeur, et continuer comme si de rien n'était (oui, cracher dans std::cerr revient à ne rien faire). Pourquoi est-ce une mauvaise chose ? Premièrement, parce qu'on ne sait pas dans quel état on est. C'est d'ailleurs pour ça que le programme se termine quand une exception est balancée depuis un destructeur : c'est la panique. Deuxièmement, que se passe-t-il si une exception d'une autre nature est lancée depuis flush ? On pourrait très bien rajouter un catch-all, mais je doute qu'il soit pertinent d'attraper tout et n'importe quoi, et gérer les exceptions n'importe comment.

                  Alors oui, j'ai déjà vu ça dans du code en production. MongoDB au hasard. Mais ils se définissent eux-même comme des anti-c++ (oui, c'est amusant quand on sait en quel langage est écrit MongoDB), ce qui montre quel type de personnes gèrent la gestion des ressources par-dessus l'épaule.

                  • [^] # Re: finally

                    Posté par . Évalué à  0 .

                    Non, l'exception n'est pas lancée dans le destructeur. Elle est lancée indirectement depuis le destructeur.

                    Tu pinailles, ça revient exactement au même…

                    Maintenant, je m'attendais à ce que tu vienne avec une solution qui est encore pire qu'un segfault : attraper l'exception dans le destructeur, et continuer comme si de rien n'était (oui, cracher dans std::cerr revient à ne rien faire).

                    Voir mon autre post en réponse à ckyl.

                    Premièrement, parce qu'on ne sait pas dans quel état on est

                    De mon point de vue, c'est justement le travail du destructeur de faire quelque chose d'approprié quand il lève une exception. Justement pour avoir un état valide à la fin. Et, si ce n'est pas possible, appeler std::terminate dans le destructeur est acceptable. Une autre solution pas trop mal, c'est de donner un "handler" à l'objet (pointeur de fonction / foncteur), qu'il peut appeler en cas d'erreurs sur une tâche asynchrone (y compris dans le destructeur). Comme ça, le programme peut faire ce qui lui semble approprié dans ce cas (et il est certainement mieux placé que le destructeur peut savoir ce qui est "le mieux" à faire d'ailleurs).

                    C'est d'ailleurs pour ça que le programme se termine quand une exception est balancée depuis un destructeur : c'est la panique.

                    Non, ton exemple s'est retrouvé dans std::terminate parce qu'une exception n'a pas été attrapée : l'exception lancée dans le destructeur de l'objet du premier morceau de code du main, après le catch (celui qui affiche "Catched exception"). Le deuxième morceau de code du main n'est, par conséquent, pas exécute (s'il était, le catch serait exécuté comme attendu et "That can't be catched" serait affiché sur la sortie standard).
                    Appeler flush et close explicitement dans l'appelant ne résout pas le problème…

      • [^] # Re: finally

        Posté par . Évalué à  6 .

        Lancer des exceptions dans un destructeur en C++, c'est le mal absolu. Il y a même des cas ou le faire provoque un comportement indéfini.

        Pour le reste, le RAII remplace le finally. Tu peux même faire une macro qui ressemble à un finally mais qui utilise du RAII en dessous: http://www.boost.org/doc/libs/1_53_0/libs/scope_exit/doc/html/index.html

    • [^] # Re: finally

      Posté par (page perso) . Évalué à  4 .

      Corrigé, merci.

      « Moi, lorsque je n’ai rien à dire, je veux qu’on le sache. » Raymond Devos

  • # foreach() + list()

    Posté par (page perso) . Évalué à  3 . Dernière modification : le 30/06/13 à 12:19

    Il me semble que l'exemple n'est pas bon. Voici ce qu'il devrait être:

    $array = [
        ["MySQL", "beaucoup utilisé"],
        ["PostgreSQL", "monte"],
        ["Oracle", "trop cher"],
    ];
    
    foreach($array as list($name, $adj) { … }

    Pas trop d'intérêt pour cet exemple, mais bon. C'est juste du sucre syntaxique pour remplacer:

    foreach($array as $tmp) {
        list($foo1, $foo2, …) = $tmp;
        /* Reste du code… */
    }

    Aussi, aucune mention de la nouvelle fonction array_column() qui est pourtant bien utile!

    $data = [ ["id" => 49, "name" => "MySQL"], ["id" => 50, "name" => "PostgreSQL"], ["id" => 42, "name" => "Oracle"] ];
    $foo = array_column($data, "name", "id");
    /*
    Renvoie: [49 => "MySQL", 50 => "PostgreSQL", 42 => "Oracle"]
    */

    J'attends avec hâte qu'il soit disponible dans les paquets Arch, PHP 5.5 apporte à mon avis d'excellente nouveautés et va dans la bonne direction.

    • [^] # Re: foreach() + list()

      Posté par (page perso) . Évalué à  1 . Dernière modification : le 30/06/13 à 16:52

      Je ne connaissais pas array_column, j'ai regardé le changelog détaillé mais je ne l'ai pas vu. C'est utile dans certains cas (assez rares je pense non ?).

      Je confirme mon erreur sur l'array, j'ai mal lu l'article, désolé. Si un modérateur peut corriger l'exemple ?

      CNRS & UNIX-Experience

  • # Red Hat a raison

    Posté par . Évalué à  -10 .

    C'est aussi pour pouvoir utiliser les dernières versions de PHP que Red Hat a du créer Red Hat Collection… :-)

    Si ma mémoire est bonne le WampServer d'alterway permettait déjà depuis longtemps de mettre différents PHP ou MySQL…
    En tout cas, il me semble que le dernier Symfony (2.3) exige du PHP 5.3+ et certaines distributions n'ont pas dans leur LTS du PHP 5.3.

    Pour ceux qui ne connaissent pas Symfony: High Performance PHP Framework for Web Development - Symfony

    Merci pour les détails…

  • # PHP makes me sad

    Posté par . Évalué à  2 .

  • # finally et sel des hashs

    Posté par (page perso) . Évalué à  3 .

    Il y a deux choses que je n'ai pas saisi:

    Déjà, à quoi sert finally? Je ne comprends pas l'explication, quelle est la différence entre:

    $con = NULL;
    try {
       $con = mysql_connect("localhost","myuser","mypwd");
       if (!$con) {
          throw new Exception("Echec de connexion à la base de données");
       }
    catch {
       echo 'Erreur MySQL : ',  $e->getMessage(), "\n";
    }
    finally {
       if ($con !== NULL) {
          close($con);
       }
    }

    et

    $con = NULL;
    try {
       $con = mysql_connect("localhost","myuser","mypwd");
       if (!$con) {
          throw new Exception("Echec de connexion à la base de données");
       }
    catch {
       echo 'Erreur MySQL : ',  $e->getMessage(), "\n";
    }
    if ($con !== NULL) {
       close($con);
    }

    ?

    Autre question, ces histoires de sel de mot de passe me paraissent étranges, comment password_get_info peut connaître le sel du hash?
    Et comment password_verify peut vérifier sans connaître le sel? (c'est un peu la même question)
    Et du coup, puisque ces deux choses semblent possible, quel est l'intérêt du sel?!

    PS: et comment on active la coloration syntaxique PHP?

    • [^] # Re: finally et sel des hashs

      Posté par . Évalué à  6 .

      Déjà, à quoi sert finally?

      finally garantit que le code qu'il contient sera exécuté après le try/catch, quelque soit l'issue (bonne ou mauvaise).
      En fait, pour bien comprendre, il faudrait plutôt un exemple comme celui-ci :

      function myFonction() {
         $con = NULL;
         try {
            $con = mysql_connect("localhost","myuser","mypwd");
            if (!$con) {
               throw new Exception("Echec de connexion à la base de données");
            }
         catch( Exception $e ) {
            echo 'Erreur MySQL : ',  $e->getMessage(), "\n";
            throw $e;
         }
         finally {
            if ($con !== NULL) {
               close($con);
            }
         }
      }

      Ici, le catch écrit un message d'erreur puis renvoie l'exception levée, donc on sort complètement de la fonction. Ce qui suit (le if de fermeture de la connexion) n'aurait jamais été exécuté s'il ne se trouvait pas dans un finally

    • [^] # Re: finally et sel des hashs

      Posté par (page perso) . Évalué à  1 .

      Hello, désolé du retard,
      pour ta question concernant les mots de passe, eh bien, j'avoue que je suis resté assez perplexe aussi…

      Pour la fonction password_verify, le sel utilisé est introduit dans le hash final, regarde ici: http://www.php.net/manual/fr/function.password-hash.php

      Pour la coloration syntaxique j'ai utilisé celle de PERL

      CNRS & UNIX-Experience

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.