Formater des numéros de téléphone belges en PHP 9

UPDATE :

Des librairies disponibles gratuitement sur Github font un travail formidable dans le formatage des numéros, et bien plus encore !

En effet, il est également possible de récupérer le nom de la ville ou encore la timezone par rapport à un numéro.
Voici un exemple de ces librairies : https://github.com/giggsey/libphonenumber-for-php

 

 

Ce matin, je devais afficher des numéros de téléphone belges. Je me souvenais que j’avais déjà fait quelques chose de similaire mais plus moyen de retomber dessus, et de toute façon, d’après mes souvenirs, c’était pas génial. J’ai donc commencé par chercher sur le net une solution toute faite afin de ne pas réinventer la roue.

Après être tombé sur quelques solutions pas géniales, j’ai trouvé un commentaire qui en gros disait « ceci pourrait être mieux fait et plus rapide avec une regex » (expression régulière).

OK très bien, commentaire constructif mais mon gars, t’en dis trop ou pas assez ! Je me suis donc mis en quête de cette fameuse regex mais sans succès, j’ai donc décidé de la construire moi-même. Voici le résultat :

/**
 * Check if a number is a valid belgian number
 *
 * @param integer $number
 * @return FALSE or type of phone number
 */
if (!function_exists('valid_be_phone_number')) {

    function valid_be_phone_number($number) {
        $ret = FALSE;
        $number = trim($number);
        if (substr($number, 0, 1) != '0' &
        &
        substr($number, 0, 1) != '+') {
            $number = '+32' . $number;
        }
        // Patterns
        $pattern = '/^((\+|00)32\s?|0)(\d\s?\d{3}|\d{2}\s?\d{2})(\s?\d{2}){2}$/';
        $pattern_mobile = '/^((\+|00)32\s?|0)4(60|[789]\d)(\s?\d{2}){3}$/';
        // Matches
        if (preg_match($pattern, $number, $matches)) {
            $ret = "fixe";
        } else if (preg_match($pattern_mobile, $number, $matches)) {
            $ret = "mobile";
        }
        return $ret;
    }

}

/**
 * Format a number as a belgian phone number
 *
 * @param integer $number
 * @param bool $internationnal : show the number in internationnal format : +32 (0) XX XX XX XX
 * @return string : formated phone number or initial string if not a valid format
 */
if (!function_exists('format_be_phone_number')) {

    function format_be_phone_number($number, $internationnal = FALSE) {
        $number = trim($number);
        if (substr($number, 0, 1) != '0') {
            if (substr($number, 0, 1) == '+') {
                $number = str_replace('+32', '', $number);
            }
            $number = '0' . $number;
        }
        $valid_phone_number = valid_be_phone_number($number);
        if ($valid_phone_number !== FALSE) {
            if ($valid_phone_number == 'mobile') {
                $pattern = '/^\s?(\d{4})\s?(\d{2})\s?(\d{2})\s?(\d{2})\s?$/i';
            } else {
                $pattern = '/^(?|(0[2349])\s?(\d{3})|(\d{3})\s?(\d{2}))\s?(\d{2})\s?(\d{2})$/i';
            }
            preg_match($pattern, $number, $matches);
            if ($internationnal) {
                $number = '+32 (0) ' . substr($matches[1], 1) . ' ' . $matches[2] . ' ' . $matches[3] . ' ' . $matches[4];
            } else {
                $number = $matches[1] . '/' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
            }
        }
        return $number;
    }

}

Quelques explications

De base, la regex n’est pas très compliquée. Le problème survient au niveau des numéros de téléphones fixes. En effet, certains numéros on un préfixe de 3 chiffres (la plupart des villes) mais les grandes villes ont un préfixe de 2 chiffres (Bruxelles [02], Anvers [03], Liège [04], Gand [09] ; voir Wikipedia). Si on ajoute à ça le fait que je voulais avoir la possibilité d’afficher le numéro au format international, je suis tombé sur un petit problème : le nombre de groupe de capture. En effet, ma première regex comptait 8 groupes de captures (ou 6 en simplifiant la regex par la suite), du coup avant de pouvoir afficher le numéro je devais faire des vérifications sur « quels groupes de capture ne sont pas vides ». Ce n’était pas vraiment génial. J’ai pas mal galéré mais l’astuce se trouve finalement dans la syntaxe (?|. Cette syntaxe que je ne connaissais pas du tout, permet de n’avoir qu’une seule référence de capture pour plusieurs groupes. Il n’y a pas vraiment plus d’infos mais vous pouvez toujours aller voir la Doc PHP qui en parle (tout en bas de la page). Dans ma regex, c’est symbolisé par ceci :

(?|(0[2349])\s?(\d{3})|(\d{3})\s?(\d{2}))

Ceci signifie que mes groupes seront soit les ce qui précède | soit ce qui le suit.

  • Si mon numéro commence par 02, 03, 04, 09, on aura donc un préfixe de 2 chiffres (groupe $1), suivit d’un nombre à 3 chiffres (groupe $2)
  • Sinon, un préfixe à 3 chiffres (groupe $1) suivi d’un nombre à 2 chiffres (groupe $2).

9 thoughts on “Formater des numéros de téléphone belges en PHP

  1. Reply charles LOEBH Mar 24,2016 21:47

    Ok! Intéressant le sujet, je vais l’étudier sérieusement pour obtenir la même chose par rapport mon pays, le Congo Brazzaville

  2. Reply lebrun r Nov 18,2016 21:43

    Bonjour,
    je reçois l’erreur ci-dessous pour le groupe d’instructions
    valid_be_phone_number($number)
    140 if (substr($number, 0, 1) != ‘0’ &
    141 &
    142 substr($number, 0, 1) != ‘+’) {
    143 $number = ‘+32’ . $number;
    144 }
    Est_il possible d’expliquer ce que fait ce groupe d’instructions
    Merci
    Parse error: syntax error, unexpected ‘;’ in C:…test.php on line 140

    • Reply Pierre Nov 18,2016 22:33

      Hmmm c’est étrange comme erreur, mais d’après le code que vous copiez/collez; vous avez écrit :

      != « 0 » &
      &

      Vous ne pouvez pas séparer les « && » pareil pour les « || ». Il s’agit de « mots de clés ». && signifie AND et || signifie OR (vous pouvez d’ailleurs écrire « AND » et « OR » à la place de « && » et « || »). Si vous mettez un des 2 caractères à la ligne, l’instruction ne signifie plus rien.

      Dites-moi si ceci à résolu votre problème, sinon je me propose de vous aider en contact privé.

  3. Reply lebrun r Nov 19,2016 16:00

    c’est un copier collé des lignes 12-16 de l’exemple ci-dessus
    & sont peut être transfomés en & ????
    Ces lignes peuvent elles s’écrivent comme suit ?
    if (substr($number, 0, 1) != ‘0’ and substr($number, 0, 1) != ‘+’)
    {$number = ‘+32’ . $number;}

    12 if (substr($number, 0, 1) != ‘0’ &
    13 &
    14 substr($number, 0, 1) != ‘+’) {
    15 $number = ‘+32’ . $number;
    16 }

  4. Reply lebrun r Nov 19,2016 16:02

    effectivement , après avoir exécuté « post comment  »
    je trouve seulement & au lieu de & amp

    • Reply Pierre Nov 19,2016 16:04

      & ou & amp; importe peu.

      Ce que je voulais dire, c’est que d’après votre copié/collé, vous un & à la ligne 12 et un autre à la ligne 13. Vous ne pouvez pas séparer les 2 é-commerciaux. Ils doivent être l’un à côté de l’autre et sur la même ligne.

  5. Reply Christophe Gesché Mai 19,2019 08:59

    Si quelqu’un lit ce post et a besoin de cas non couverts par le package de validation spécifique à la Belgique de PEAR : https://github.com/pear/Validate_BE

    N’hésitez pas à le décrire dans https://pear.php.net/bugs/report.php?package=Validate_BE

    Même si PEAR semble à l’abandon, ses packages les plus simples restent disponible et fonctionnels

    • Reply Pierre Mai 21,2019 09:57

      C’est vrai que je n’ai jamais updaté ce post mais je vais le faire.
      En effet, il existe de nombres lib disponibles sur github qui couvrent tous les numéros de téléphones du monde et qui permettent même de trouver la ville ou la timezone en fonction du numéro.
      Voici un exemple de librairie vraiment utile : https://github.com/giggsey/libphonenumber-for-php

Leave a Reply

  

  

  

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.