Facebook LinkedIn SourceForge Twitter RSS LastFM
logologo

Réimplémenter la fonction file_put_contents() en PHP

Geoffray Warnants|26/08/2013|62 commentaires

J'en convient, l'ide de vouloir faire pareille chose peut paratre farfelue. Et pourtant ! Quelle ne ft pas ma surprise, lorsque lors d'une intervention sur une application dont on m'avait innocemment cach les caractristiques de l'hbergement, je me suis rapidement retrouv face l'erreur :

Fatal error: Call to undefined function: file_put_contents()

Et pareil constat avec sa consoeur :

Fatal error: Call to undefined function: file_get_contents()

Je crus d'abord une farce. Puis une restriction volontaire de l'hbergeur via la directive disable_functions, ne cessant nanmoins de me demander quelle obscure raison pouvait motiver cet acte de pur sadisme. Mais un rapide phpinfo() me rvla bien vite la triste ralit de la situation : j'tais l sur un antdiluvien serveur PHP 4.2, et ces fonctions aujourd'hui combien familires n'existaient tout simplement pas encore dans cette antique version du langage parue en 2002 !

Mme si les statistiques mondiales collectes par w3techs.com (aot 2013) permettent d'estimer qu'aujourd'hui moins de 3% des hbergements PHP fonctionnent encore en PHP 4 et que ce chiffre tend lentement vers 0 dans une longue agonie, voici malgr tout un patch permettant de rendre vie ce couple de fonctions bien utiles. Bien conscient du peu d'intrt qu'il pourra susciter, je le ddie spcialement au prochain Marty McFly du web qui se retrouvera tout comme moi propuls dans une lointaine poque.

if (!function_exists('file_put_contents')) {
    function file_put_contents($filename, $data, $flags=0, $context=null) {
        $fopen_args = array(
            $filename,
            (($flags&FILE_APPEND) == FILE_APPEND) ? 'a' : 'w',
            (($flags&FILE_USE_INCLUDE_PATH) == FILE_USE_INCLUDE_PATH)
        );
        if (is_resource($context)) {
            $fopen_args[] = $context;
        }
        if (($fd = call_user_func_array('fopen', $fopen_args)) !== false) {
            if (($flags&LOCK_EX) == LOCK_EX && !flock($fd, LOCK_EX)) {
                fclose($fd);
                return false;
            }
            for ($written=0, $l=strlen($data); $written < $l; $written += $nb) {
                if (($nb = fwrite($fd, substr($data, $written))) === false) {
                    if (($flags&LOCK_EX) == LOCK_EX) {
                        flock($fd, LOCK_UN);
                    }
                    fclose($fd);
                    return false;
                }
            }
            if (($flags&LOCK_EX) == LOCK_EX) {
                flock($fd, LOCK_UN);
            }
            fclose($fd);
            return $written;
        }
        return false;
    }
}

if (!function_exists('file_get_contents')) {
    function file_get_contents($filename, $use_include_path=false, $context=null, $offset=-1, $maxlen=-1) {
        $fopen_args = array($filename, 'r', $use_include_path);
        if (is_resource($context)) {
            $fopen_args[] = $context;
        }
        if (($fd = call_user_func_array('fopen', $fopen_args)) !== false) {
            if ($offset > 0) {
                fseek($fd, $offset);
            }
            $buffer = '';
            while (!feof($fd) && ($maxlen < 0 || ($r=$maxlen-strlen($buffer)) > 0)) {
                if (($data = fread($fd, ($maxlen < 0 || $r > 8192) ? 8192 : $r%8192)) === false) {
                    fclose($fd);
                    return false;
                }
                $buffer .= $data;
            }
            fclose($fd);
            return $buffer;
        }
        return false;
    }
}

Ragir cet article | Lire la suite >>>

jClockClock aux Open du Web de Paris

Geoffray Warnants|03/04/2012|44 commentaires

Le 14 mars dernier se droulait Paris la premire dition des Open du Web, un challenge runissant une quarantaine de participants chevrons venus s'affronter autour d'une srie d'preuves de dveloppement web, intgration, web-design, rfrencement naturel et administration systme.

Si j'en parle aujourd'hui, ce n'est pas que j'tais de la partie, mais plutt parce que l'un de mes scripts a t choisi pour incarner le rle du mchant compte rebours gant, projet sur plusieurs crans surplombants la salle, et dcomptant sans piti les prcieuses secondes des 2h30 accordes aux candidats pour accomplir un maximum d'preuves.

C'est en effet mon horloge jClockClock dveloppe il y a quelques temps en Javascript, qui s'est vue spcialement adapte et relooke le temps d'une soire par l'agence Moon Websites, organisatrice de l'vnement. Un trs bel exemple d'intgration qui mrite d'tre flicit. Vivement la seconde dition !

Open du Web Open du Web Open du Web Open du Web Open du Web Open du Web

Ragir cet article | Lire la suite >>>

Ma première contribution au manuel PHP

Geoffray Warnants|24/05/2011|36 commentaires

Au cours de mes recherches dans les profondeurs de la documentation PHP, il m'arrive assez frquemment de rencontrer des anomalies diverses comme des prototypes de fonction incomplets, de grossires fautes d'orthographe ou des phrases peine plus comprhensibles que celles gnres par un traducteur automatique. Autant de dtails dont l'importance peut paratre insignifiante mais qui contribuent dcrdibiliser le srieux du langage. Et pourtant, en ingrat dveloppeur que je suis, j'avoue n'avoir jamais pris la peine d'informer la communaut PHP de ces dfauts, sombrant de jours en jours en peu plus loin dans le pch.

Jusqu'au jour o ma bonne conscience se rveilla, probablement illumine par une intervention de notre bienveillant Dieu Rasmus, qui de tout l-haut ramne ses fidles dveloppeurs dans le droit chemin. Au cours de cette divine apparition, il me pardonna puis me rappela l'existence de son outil de rapport de bugs et insista sur le fait que les problmes lis la documentation y sont bien entendu accepts, car tout bug est gal son prochain.

Je me suis donc depuis lors acharn signaler le moindre problme rencontr, et c'est ainsi plus d'une centaine de corrections qui ont t envoyes, approuves puis appliques notre manuel chri. Sans vouloir imiter Frdric Hardy et ses Nouvelles du front, voici l'inventaire des modifications apportes aux prototypes de nombreuses fonctions :

#54747, #54748, #54749, #54750, #54751, #54752, #54753, #54754, #54755, #54756, #54757, #54761, #54762, #54763, #54768, #54770, #54771, #54772, #54773, #54779, #54780, #54781, #54782, #54783, #54784, #54785, #54786, #54787, #54788, #54789, #54790, #54793, #54794, #54795, #54796, #54797, #54800

Celles-ci, plus anecdotiques, concernent essentiellement des corrections orthographiques dans la documentation francophone et des erreurs releves dans les scripts d'exemple.

#54806, #54807, #54808, #54809, #54810, #54811, #54812, #54813, #54814, #54815, #54816, #54817, #54818, #54819, #54820, #54822, #54823, #54825, #54826, #54827, #54828, #54829, #54830, #54833, #54834, #54835, #54836, #54837, #54838, #54839, #54840, #54841, #54845, #54846, #54847, #54848, #54849, #54850, #54853, #54854, #54855, #54856, #54857, #54858, #54868, #54869, #54872, #54873, #54874, #54875, #54876, #54877, #54878, #54879, #54880, #54881, #54882, #54883, #54884, #54885, #54886, #54887, #54889, #54890, #54891

Une dmarche apparemment trop peu frquente, puisqu'elle a suscit la curiosit de plusieurs membres minents de la Documentation Team comme Peter Cowburn, Richard Quadling ou Pierrick Charron, visiblement soucieux de mon intgrit humaine. Je ne peux donc qu'encourager chaque dveloppeur participer, ds qu'il en a l'opportunit, l'amlioration de ce formidable outil dont nous profitons tous gostement. Un simple acte citoyen suffit tmoigner de la reconnaissance envers les nombreux anonymes bnvoles dont les contributions nous furent, un jour ou l'autre, d'une aide plus que prcieuse.

Ragir cet article | Lire la suite >>>

Un géocodeur Javascript utilisant l'API Google Maps V3

Geoffray Warnants|16/02/2011|40 commentaires

Que ce soit lors de mes dveloppements ou dans la vie de tous les jours, il m'arrive frquemment de vouloir trouver les coordonnes GPS d'un lieu bien prcis, en gnral partir de son adresse postale, mais aussi parfois en prfrant le localiser sur une carte s'il s'agit par exemple d'un endroit isol au beau milieu de la savane.

Vu que ni Google Maps, Bing ou Mappy ne nous autorisent faire a simplement, j'ai dcid de crer une modeste application de gocodage rpondant mes besoins.
Base sur l'API Javascript V3 de Google Maps, elle permet d'obtenir la latitude et la longitude d'une adresse postale o d'un marqueur pouvant tre dplac sur la carte. L'opration inverse (reverse geocoding) est galement possible, dvoilant donc l'adresse d'un lieu dsign par ses coordonnes GPS.

J'invite ceux qui seraient intresss par la manire d'intgrer ces services Google jetter un oeil au code qui se rsume en quelques lignes de Javascript d'une tonnante simplicit, et ce grce leur API formidablement bien pense. Pour tout complment d'information, la documentation est tout aussi complte.

Demo

Ragir cet article | Lire la suite >>>

Convertir des nombres en base 62 avec PHP

Geoffray Warnants|09/02/2011|77 commentaires

Dans la continuit du billet trs intressant de Vincent Battaglia consacr l'utilit du systme de numration hexatridcimal (soit en base 36) dans l'algorithme d'un raccourcisseur d'URL, j'ai voulu savoir si utiliser d'autres systmes de numration encore plus vastes, comme le base 62 voqu la fin de son article, pouvait se faire avec autant de facilit, ce qui permettrait de gnrer des URL encore plus courtes moindre effort.

Comme il l'a dj bien expliqu, le principal critre qui influencera le choix entre l'une de ces deux bases est certainement le souci de la sensibilit la casse. En effet, la base 36 se concentre sur le systme alphanumrique minuscule tandis que la base 62 inclut aussi les caractres majuscules.

D'autre part, il va videmment de soi qu'au plus la base est leve (autrement dit au plus l'ventail de symboles possibles est vaste), au plus un nombre peut-tre reprsent de manire concise. Dans le cadre des raccourcisseurs d'URL, c'est donc aussi un critre primordial. Non seulement pour l'conomie de caractres que cela implique, mais aussi pour le nombre d'identifiants que le service pourra grer, et donc le nombre d'URL qu'il pourra prtendre offrir. Bien que la plupart des services actuels comme TinyURL, bit.ly ou goo.gl semblent s'tre limits une base 62, d'autres sont plus aventureux, comme par exemple le service (belge, disons-le !) http://ui.tl qui affirme tre le plus concis du march par l'utilisation d'une base 163, prenant ainsi le risque d'inclure des caractres accentus dans ses rsultats.

Lors de la mise en pratique, je fus tout d'abord surpris de dcouvrir que la fonction base_convert de PHP ne supporte pas la conversion d'un nombre en base 62. L'occasion tant trop tentante, j'en ai profit pour rcrire une fonction sensiblement identique permettant cette fois de jongler entre diffrentes bases arbitraires avec une totale libert.
Par la mme occasion, j'y ai ajout au travers d'un dernier paramtre optionnel la possibilit de spcifier le jeu de caractres prendre en compte lors de la conversion. J'y vois plusieurs cas d'utilisation concrets, comme par exemple :

  • Pouvoir djouer le caractre prdictif inhrent ce genre de conversion, en spcifiant un alphabet dont l'ordre aura t pralablement altr.
  • Pouvoir gnrer des valeurs "user-friendly", en omettant par exemple les caractres susceptibles de prter confusion lors de la lecture, tels o,O,0,1,l, etc...
  • Pouvoir dfinir son propre jeu de caractres, qui pourrait par exemple inclure des caractres spciaux.
/**
 * Convertit un nombre entre diffrentes bases.
 *
 * @param   string      $number     Le nombre  convertir
 * @param   int         $frombase   La base du nombre
 * @param   int         $tobase     La base dans laquelle on doit le convertir
 * @param   string      $map        Eventuellement, l'alphabet  utiliser
 * @return  string|false            Le nombre converti ou FALSE en cas d'erreur
 * @author  Geoffray Warnants
 */
function base_to($number, $frombase, $tobase, $map=false)
{
    if ($frombase<2 || ($tobase==0 && ($tobase=strlen($map))<2) || $tobase<2) {
        return false;
    }

    if (!$map) {
        $map = implode('',array_merge(range(0,9),range('a','z'),range('A','Z')));
    }

    // conversion en base 10 si ncessaire
    if ($frombase != 10) {
        $number = ($frombase <= 16) ? strtolower($number) : (string)$number;
        $map_base = substr($map,0,$frombase);
        $decimal = 0;
        for ($i=0, $n=strlen($number); $i<$n; $i++) {
            $decimal += strpos($map_base,$number[$i]) * pow($frombase,($n-$i-1));
        }
    } else {
        $decimal = $number;
    }

    // conversion en $tobase si ncessaire
    if ($tobase != 10) {
        $map_base = substr($map,0,$tobase);
        $tobase = strlen($map_base);
        $result = '';
        while ($decimal >= $tobase) {
            $result = $map_base[$decimal%$tobase].$result;
            $decimal /= $tobase;
        }
        return $map_base[$decimal].$result;
    }
    return $decimal;
}

Pour se faire une ide de l'allure que peuvent avoir les valeurs retournes par cette fonction, voici titre indicatif les rsultats d'une srie de conversions entre diffrentes bases. En ce qui concerne la base 163, j'ai considr le jeu de caractres revendiqu par le service http://ui.tl.

base 10 base 16 base 36 base 62 base 163
100 64 2s 1C Æ
1000 3e8 rs g8
10000 2710 7ps 2Bi e%
100000 186a0 255s q0U %}I
1000000 f4240 lfls 4c92 OIÌ
10000000 989680 5yc1s FXsk $6Ô@
100000000 5f5e100 1njchs 6LAze @gÉ1
1000000000 3b9aca00 gjdgxs 15FTGg #5Û#.
10000000000 2540be400 4ldqpdk aUKYOs 6^/5Ç

Ragir cet article | Lire la suite >>>

<<< Articles plus rcents | Articles plus anciens >>>

zend framework