IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Expression régulière vs explode


Sujet :

Langage PHP

  1. #1
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut Expression régulière vs explode
    Bonjour tout le monde,


    Je dois décomposer des données de ce type :

    [1] => 178.255.215.78 - - [16/Mar/2013:03:00:32 +0100] "GET /saint-egreve-38120/homeopathe/ HTTP/1.1" 200 6886 "-" "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)"
    De prime abord, je me serais lancé dans des explodes dans tous les sens.

    Puis, je me dis que des expressions régulières seraient peut être mieux.


    Qu'en pensez-vous ?


    Merci
    Vincent Pieplu
    Développeur Site Internet

  2. #2
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juin 2004
    Messages : 108
    Points : 175
    Points
    175
    Par défaut
    Bonjour,

    Personnellement j'aurais sans hésité utilisé des expressions régulières . Il y a trop de caractères différents dans le schéma pour des explodes. De plus certains caractères comme dans l'adresses peuvent être différents (je pense particulièrement au "-" qui avec un explode va faire un peu n'importe quoi en cas de rencontre ).

  3. #3
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    J'en suis ici pour le moment, mais je bloque

    http://regexr.com?345au
    Vincent Pieplu
    Développeur Site Internet

  4. #4
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 867
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 867
    Points : 6 581
    Points
    6 581
    Par défaut
    Bonjour,

    j'aurais sans hésité utilisé des expressions régulières
    C'est clair et net!

    gskinner.com ça à l'air sympa comme outil en ligne. Bref!

    Ton code ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}) - - (.*]) "(.*/ HTTP\b)/gi
    ... (Je le post ici pour éviter d'avoir à changer de page en lisant le thread) ne marche pas car tu as commis quelques erreurs:

    - tu utilises / pour délimiter ton expression donc fatalement en arrivant à (.*/ le parser est persuadé que ton expression est terminée et que le H de HTTP\b)/gi est un nouveau modifier tout droit venu de la planète Zoltar. Donc soit tu échappes avec un antislash pour signifier que tu veux bien parler du caractère / et pas du délimiteur, soit tu choisis un autre délimiteur (+mieux) que tu es sûr de ne pas croiser toutes les trois secondes dans la chaîne à traiter. (par exemple ` ou #)
    - tu as pris le parti de ne pas vérifier si l'adresse ip est valide (ie: ce n'est pas le but) donc autant aller au plus court ((?:\d{1,3}\.){3}\d{1,3}) (au passage, on note que le point est échappé car il s'agit du caractère . et pas du caractère universel.)
    - le modifier g n'existe pas en PHP, la recherche global est déterminée par l'utilisation de preg_match_all.
    - le modifier i ne sert peut-être pas à grand chose dans le cas présent, autant s'en passer si toutes les lignes sont calibrées comme des tomates. (à voir)
    - tu devrais soit dégloutonner ponctuellement les quantifiers (* ou +) avec un ? (--> .*?) soit faire un dégloutonnage général en ajoutant le modifier U à la fin de la pattern.
    - préférer + à * si on est sûr d'avoir au moins un caractère
    Ce qui nous donne:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    $string = <<<LOD
    178.255.215.78 - - [16/Mar/2013:03:00:32 +0100] "GET /saint-egreve-38120/homeopathe/ HTTP/1.1" 200 6886 "-" "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)"
    143.212.13.18 - - [12/Jan/2056:07:13:32 +0100] "GET /sainte-benedicte-gardes-nous-du-mal-72143/rebouteux/ HTTP/1.1" 405 6886 "-" "Baiduspider ( http://www.baidu.com/search/spider.htm )"
    LOD;
    $pattern = '`((?:\d{1,3}\.){3}\d{1,3}) - - (.+]) "(.+/ HTTP)`U';
    preg_match_all( $pattern, $string, $matches );
    ?><pre><?php
    print_r( $matches);
    ?></pre>

    Bon courage pour la suite
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 34
    Points : 41
    Points
    41
    Par défaut
    Citation Envoyé par TERRA126 Voir le message
    Personnellement j'aurais sans hésité utilisé des expressions régulières .
    Pour moi, c'est totalement l'inverse :-)

    À première vue, c'est un log apache, cela se parse super bien avec un explode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    <?php
    $string = '178.255.215.78 - - [16/Mar/2013:03:00:32 +0100] "GET /saint-egreve-38120/homeopathe/ HTTP/1.1" 200 6886 "-" "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)"';
     
    $explode = explode(' ', $string);
     
    // Données qui ne changeront jamais de place
    $ip = $explode[0];
    $date = $explode[3].' '.$explode[4];
    $method = $explode[5];
    $url = $explode[6];
    $version_http = $explode[7];
    $status_code = $explode[8];
    $size = $explode[9];
    $referer = $explode[10];
     
    // Pour le user agent, on récupére ce qui reste
    for ($i = 0; $i < 11; $i++) {
      unset($explode[$i]);
    }
    $user_agent = implode(' ', $explode);
     
    echo "
    ip : $ip
    date : $date
    method : $method
    url : $url
    version_http : $version_http
    status_code : $status_code
    size : $size
    referer : $referer
    user_agent : $user_agent
    ";

  6. #6
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juin 2004
    Messages : 108
    Points : 175
    Points
    175
    Par défaut
    En fait pourquoi les regex ? parce que j'aurais plus tendance à vouloir récupérer les informations par domaine et ensuite m'occuper de chaque domaine un à un. Du moins c'est ce que je fais dans mes codes et je trouve que cela donne une bonne séparation des taches .

    De plus en faisant comme cela, se reporter à la doc apache est fait plutôt simplement :

    %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"
    devient donc :

    ^(\S+) \S+ \S+ \[([^\]]+)\] "([A-Z]+[^"]*)" \d+ \d+ "[^"]*" "([^"]*)"$
    Soit dit en passant je peux aussi récupérer les informations de manières segmenter en rajouter des groupes. Mais bon, après il existe plusieurs méthodes c'est vrai, savoir laquelle est la bonne est assez subjectif .

  7. #7
    Candidat au Club
    Inscrit en
    Mars 2013
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2013
    Messages : 5
    Points : 4
    Points
    4
    Par défaut
    Tu peux aussi faire une recherche dans le string

  8. #8
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 867
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 867
    Points : 6 581
    Points
    6 581
    Par défaut
    C'est vrai que mis à part le date_time et le referer, tout le reste se sépare bien de la même façon avec les espaces. Du coup, la description précise des séquences de caractères comme l'adresse ip perd de son intérêt.
    Il faut voir aussi qu'avec explode on se retrouve avec des " isolés dans les résultats à traiter avec trim et consortes.

    Maintenant un autre intérêt de preg_match_all est aussi d'obtenir un résultat facilement exploitable à l'aide de sous-masques nommés.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?php $string = <<<LOD
    178.255.215.78 - - [16/Mar/2013:03:00:32 +0100] "GET /saint-egreve-38120/homeopathe/ HTTP/1.1" 200 6886 "-" "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)"
    127.0.0.1 - - [20/Mar/2013:22:51:33 +0100] "GET /css/style.css HTTP/1.1" 200 1603 "http://truc/" "Opera/9.80 (X11; Linux x86_64; Edition Linux Mint) Presto/2.12.388 Version/12.12"
    127.0.0.1 - - [21/Mar/2013:07:39:31 +0100] "OPTIONS * HTTP/1.0" 200 126 "-" "Apache/2.2.22 (Ubuntu) (internal dummy connection)"
    LOD;
     
    // définition des champs utiles et du masque correspondant pour créer la pattern
    $fields = array( 'remote_host', 'log_name', 'user_id', 'date_time', 'request', 'method', 'request_url', 'protocol', 'status', 'size', 'referer', 'user_agent' );
    $mask = '`^(?<%s>.+) (?<%s>.+) (?<%s>.+) \[(?<%s>.+)] "(?<%s>(?<%s>.+) (?<%s>.+) (?<%s>.+))" (?<%s>.+) (?<%s>.+) "(?<%s>.+)" "(?<%s>.+)"$`Um';
    $pattern = vsprintf( $mask, $fields );
     
    preg_match_all( $pattern, $string, $matches, PREG_SET_ORDER );
     
    // récupération du résultat et élimination des variables inutiles
    $result = array();
    $fields = array_flip( $fields );
    foreach ($matches as $match) { $result[] = array_intersect_key( $match, $fields ) ; }
    unset ($fields, $mask, $pattern, $matches, $match);
     
    ?><pre><?php print_r( $result  ); ?></pre>
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #9
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    Merci pour tous vos codes, je n'ai que l’embarras du choix

    Comme l'avais vu leviathan516, c'est un log apache que je dois étudier.
    J'aimerais, à des fins persos, pouvoir analyser ce log.
    Le problème, c'est que chaque jour, le log fait près de 1 millions de lignes pour 230 Mo.

    Du coup, ça pose problème de "allowed memory".
    Apparemment, le fait d'avoir rajouté...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ini_set ('memory_limit', filesize ($chemin) + 4000000);
    ... permet de ne pas bloquer sur le file_get_contents. Par contre, ca plante sur l'explode.

    L'idée qui me venait donc, qui n'est pas forcément la meilleure, couper par paquet de lignes, mais je n'ai pas trouvé le bon logiciel

    Je suis preneur de toute idée

    Merci
    Vincent Pieplu
    Développeur Site Internet

  10. #10
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juin 2004
    Messages : 108
    Points : 175
    Points
    175
    Par défaut
    En fait pour ce genre d’opération sur ce type de fichier je te conseillerais plus de te tourner directement vers un script perl . Ce langage est fait pour gérer les très gros fichier et plutôt adapter à ce que tu veux faire .

  11. #11
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut,

    sans aller jusqu'au PERL, tu peux utiliser fread et/ou toutes les autres fonctions commençant par f...
    C'est séquentiel, lent mais cela devrait éviter les dépassements de mémoire

  12. #12
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    J'ai le même problème en faisant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $handle = fopen($chemin, "r");
    $contenu_string = fread($handle, filesize($chemin));
    echo '<pre>'.print_r($contenu_string, true).'</pre>';
    Fatal error: Allowed memory size of 239928367 bytes exhausted (tried to allocate 235929600 bytes)
    Vincent Pieplu
    Développeur Site Internet

  13. #13
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Bon, je t'ai pas filé la soluce clé en main mais quand même c'était trouvable, non ?
    Tiens inspire-toi de fgets() et fais gaffe à auto_detect_line_endings

    Dans ton code tu passes : filesize comme longueur à lire ! Aucune utilité.

  14. #14
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    Dans la code, c'est marqué de faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    ini_set("auto_detect_line_endings", true);
     
    $handle = fopen($chemin, "r");
    if ($handle) {
        while (($buffer = fgets($handle, 4096)) !== false) {
            echo $buffer;
        }
        if (!feof($handle)) {
            echo "Erreur: fgets() a échoué\n";
        }
        fclose($handle);
    }
    Est ce là solution ?? Car mon chrome plante au bout d'un certain temps
    Vincent Pieplu
    Développeur Site Internet

  15. #15
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Oui,
    s'il plante c'est que ton traitement a atteint la durée maximale d'exécution d'un script sur ton serveur.
    Je t'avais prévenu : c'est séquentiel, lent et donc à problème.
    Après parser des gros logs avec PHP c'est moyen moyen.
    PHP n'est pas des plus adaptés, il faut savoir rester mesuré dans la volumétrie.

  16. #16
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    Le problème, ce log, c'est une seule journée que je voudrais analyser.
    Tu aurais une idée de comment je peux faire ?

    Diviser le fichier en paquet ?
    Vincent Pieplu
    Développeur Site Internet

  17. #17
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Abandonne PHP pour faire ça, il existe des outils open source qui le font très bien comme AWStats par exemple.
    Bref, PHP est fait pour générer du HTML, requêter de la base de données en pagaille et c'est à peu près tout. Au-delà ce n'est plus trop de son domaine (sauf si l'usine à gaz est permise)

  18. #18
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    J'étais bien tombé sur AWStats, le problème, ou alors je n'ai pas vu, c'est que je vois pas les stats sur le fichier de log.

    Par exemple, est ce que je peux savoir cb de fois une même IP est appelée ?
    Vincent Pieplu
    Développeur Site Internet

  19. #19
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Euh... combien de fois une IP est appelée ?
    Si elle est appelée c'est par le navigateur du client, donc toi t'en sauras rien à moins d'envoyer une requête au préalable à ton serveur pour l'informer que ce lien a été cliqué dans la page (en dehors de ton domaine bien sûr).

    Si c'est pas ça, c'est que je n'ai rien compris alors.

  20. #20
    Membre régulier Avatar de PIEPLU
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    507
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 507
    Points : 92
    Points
    92
    Par défaut
    Dans mon fichier de log, j'ai les IP de ceux qui accède à des pages...
    Parfois, j'ai des centaines de pages lancées par la même IP dans la même minute...

    Le but, c'était de les détecter, pour les bloquer.
    Vincent Pieplu
    Développeur Site Internet

Discussions similaires

  1. [PHP 5.2] Explode et expression régulière
    Par renaud26 dans le forum Langage
    Réponses: 3
    Dernier message: 30/03/2011, 17h01
  2. [RegEx] explode, strstr, str.. utilise des expressions régulières ?
    Par newbie_php dans le forum Langage
    Réponses: 7
    Dernier message: 01/02/2010, 21h34
  3. [expression régulière] mon cerveau fait des noeuds..
    Par nawac dans le forum Algorithmes et structures de données
    Réponses: 7
    Dernier message: 27/05/2003, 10h06
  4. Expressions réguliéres
    Par Tooms dans le forum Langage
    Réponses: 4
    Dernier message: 06/12/2002, 18h42
  5. Réponses: 5
    Dernier message: 11/06/2002, 15h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo