problème de regex de détection des #

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : problème de regex de détection des #

par titerm » 17 déc. 2007, 12:20

En gros c'est ça.
Si tu fais un preg_replace, tu peux faire 2 regexp dans un tableau, cela à le mérite de bien les séparer
Sinon, tu fait tout bêtement des alternative au sens regexp du terme

(regexp1 | regexp2), et si tu ne souhaites pas capturer (gain en perf et ram), (?: regexp1 | regexp2)


Pour les listes des protocoles, je te souhaites bien du courage :)
En voila un court extrait, en sachant que la liste, en fait, n'est pas close. Il manque tous les protocoles p2p, par exemple.

http://www.iana.org/assignments/uri-schemes.html

par BeRoots » 17 déc. 2007, 11:28

si je comprend bien, je fait une regex comme celle que tu m'a mis en fin de post, puis une pour le url sans protocole? c'est ça :-k

sinon pour ce qui est du protocole file://, j'ai remarqué que sous win il s'ecrit via 3 slash alors que sous linux il m'est pas ecrit mais il s'interprete bien via 2 slash (mac aucune idée)... donc c'est pour ça que je j'ai virer (en cas de doute s'abstenir);)

si quelqu'un a un complement d'info a ce sujet ;)

par titerm » 16 déc. 2007, 18:36

Ok. Pour file://, cela n'a rien de spécifique a windows. C'est un protocole comme un autre.

Concernant ta regex, attention aux perfs. Personnellement, plutot que de faire une seul regexp qui match tout, je prendrait la regex qui match les urls aux normes, et je ferais une alternative pour gérer l'exception type www.domain.fr

Pour info,
Avec le sujet

Code : Tout sélectionner

http://www.domaine.fr/dossier/fichier.php?qq=1&qq2=e%20+e:azerty<br />
Ta regexp match 1en 70 etapes, et va faire 230 etapes pour couvrir toute la string, de plus, tu captures 9 chaines... Capture uniquement ce dont tu te serts.

Code : Tout sélectionner

(((file|ed2k|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(file:///)|(www\.))+(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(/[-a-zA-Z0-9&+@=?#/%_|!:,.;~]*)?
Cette regexp match en 22 étapes et va faire 76 etapes pour couvrir la string

Code : Tout sélectionner

\b(?>file|ed2k|gopher|news|nntp|telnet|https?|ftps?|sftp)://[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|]
En faisant une bete alternative a la regexp précédante, tu ne peux être que gagnants. Déjà, la partie 1 de la regexp est réutilisable pour des url normées, ensuite, en scindant en 2 alternatives, tu simplifies le debug et tu gagnes en perfs.

Ce n'est qu'un avis perso.

par BeRoots » 16 déc. 2007, 11:46

merci pour ce complement d'info :)
mon obfectif à moi était de récuperer tout les type d'url possible (au norme ou nom), pour une simple détection et remplacement dans du comtenu ou je n'autorise pas email et url...
ma classe de filte fonctionne tres bien comme cela (j'ai juste virer le protocole file:/// car trop spécifique Windows et ne tient pas réelement compte des spécification d'une url :-k

en tout cas merci à tous pour vos divers aides :)

par titerm » 16 déc. 2007, 11:38

@beroot.

Je n'antislash pas le point car il est dans un "classe" de caractères [].. Dans une classes, le point n'a pas de signification particulière, pas plus que * ou ?, seul ^-]\ ont des significations particulière au sein d'une classe et leurs significations peu varier en fonction de leur emplacement dans la classe.
Eg [-az] ou [a-z], signifier '-' ou 'a' ou 'z' dans le premier cas, et n'importe quelle minuscule dans le second.

la regexp que je t'ai donné match tous les exemples que tu as cités pour l'instant a l'exception de www.domaine.fr qui, amha, n'est plus réellement une url. A vouloir matcher trop de chose, tu risque de matcher tout ou plus que souhaiter.

par Hywan » 15 déc. 2007, 20:10

Parser une URL n'est pas si compliqué que ça. Il suffit de lire les RFCs. Plus particulièrement, la numéro 2396 et 3986.
Elle nous dit entre autre, que la forme d'une URL (ou URI ; mieux) est :

Code : Tout sélectionner

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
On peut alors appliquer la regex de la RFC :

Code : Tout sélectionner

Regex 1 : #^(?:([^:/?\#]+):)?(?://([^/?\#]*))?([^?\#]*)(?:\?([^\#]*))?(?:\#(.*))?#
On l'applique sur :

Code : Tout sélectionner

scheme://authority/path/to/file.php?query=value#fragment
Avec ces expressions régulières, on récupère le scheme, l'authority, le path, la query, et le fragment (le procole, le nom de domaine, le chemin, la requête, et l'ancre).
Après, on peut appliquer une décomposition additionnelle avec la regex suivante sur l'authority, qui est de la forme : L'expression est :

Code : Tout sélectionner

Regex 2: #^(?:([^:@]+):([^@]+)@)?([^:]+)(?::(.*))?$#
On pourra alors récupérer le nom d'utilisateur, le mot de passe, l'authority plus précis, et le port.

Si tu veux tester toutes les parties de l'URI, jette un oeil à la partie Appendix A. Collected (A)BNF for URI. Il faut faire en gros 15 autres regex qui se recoupent les unes les autres. Je ne mets le code ici pour ne pas alourdir, surtout que tout se trouve dans les RFCs. Il faut regarder les types alpha, digit, alphabum, mark, gen-delims, sub-delims, reserved, unreserved, pct-encoded, uric, pchar, segment, segment-nz, path-absolute, et reg-name. Rien que ça, oui Monsieur. La plupart se recoupe, ou se recompose, heureusement.

J'ai fais une classe qui gère la validité d'une URI, mais ce sera avec mon framework. J'espère le sortir pour janvier 2008. Je peux néanmoins te fournir les codes avant :). Ou alors (et j'aimerais beaucoup) faire un tutorial pour PHPFrance sur la validation des URIs :).

Voilà, bonne lecture des RFCs !

par BeRoots » 15 déc. 2007, 19:28

disons qu'elle est complexe mais elle me capture tout type d'url ou presque (www.domaine.fr ; http://127.0.0.1 ; file:///proram~01/fichier.tif et bien plus encore) :)

je viens de la modifier un peu pour prendre aussi les url de type ftp://user1:[email protected] :p
@Titerm: pourquoi n'antislashe tu pas le . dans ta classe?
\b(https?|ftp|file)://[-\w+&@#/%?=~_|!:,.;]*[-\w+&@#/%=~_|]

et aussi, voit tu des simplifications à apporter à cette regex pour une même détection de tout type d'url
si quelqu'un peut aussi me dire si il connait d'autre protocole genre htp ftp... qui ne serai pas enoncer dans cette regex ;)

sinon, je vais refaire une flopper de test en local pour voir ;)

par titerm » 15 déc. 2007, 19:14

Après test, ta reg ne capture pas plus loin que le y de azerty dans ton exemple :

Code : Tout sélectionner

http://www.domaine.fr/dossier/fichier.php?qq=1&qq2=e%20+e:azerty<br />
Soit tu tombes sur un bug du moteur pcre de php, soit, tu utilises encore un formulaire aproximatif pour l'évaluation de tes regexp... :), mais la reg, bien que complexe (trop ? ) capture l'url uniquement.

par BeRoots » 15 déc. 2007, 19:06

@Berzemus: refert toi au RCF822 et autes... pour voir ce qu'il en retourne point de vue normalisation des url ;)

@Titerm: pourquoi n'antislashe tu pas le . dans ta classe?

pour ce qui est de la non capture de mes balises html lors de la détection d'url, je ne m'explique toujour pas pourquoi ma regex capture celle-ci :-k
§(((file|ed2k|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(file:///)|(www\.))+(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(/[-a-zA-Z0-9&+@=?#/%_|!:,.;~]*)?§
pourtant ma classe de catractère ne contient pas le < donc il ne devrai pas être détecter nan?
[-a-zA-Z0-9&+@=?#/%_|!:,.;~]

si quelqu'un à une idée ;)

par titerm » 15 déc. 2007, 15:07

Voila une base que tu peux compléter

Code : Tout sélectionner

\b(https?|ftp|file)://[-\w+&@#/%?=~_|!:,.;]*[-\w+&@#/%=~_|]

par Berzemus » 15 déc. 2007, 14:51

ça doit être si compliqué que ça le regex d'url ?

En toute vitesse, je trouve ceci: (sous peine que l'url débute avec http://)

Code : Tout sélectionner

http:[A-Za-z0-9/.?=&%+:]+
mais y'a de quoi améliorer..

par titerm » 15 déc. 2007, 14:47

Ah oui, désolé pour les smileys... Je regarderais ton dernier pb plus tard, la ma fille me tanne pour les déco de noël... :)

par BeRoots » 15 déc. 2007, 13:22

ok c'était bein ça :)

PS. pense à mettre entre balise code tes regex histoire d'éviver les smileys :lol:

Code : Tout sélectionner

§(?<!:|:/)/{2,}§
Par contre si quelqu'un à une idée ou une méthode sur mon problème de non détection des <br /> en fin d'url ;)

merci d'avance :)

par titerm » 15 déc. 2007, 13:11

uhmmm j'ai pas de php sous la main, pe un pb dans le moteur pcre de php...

essai avec des assertions à longueur fixe

Code : Tout sélectionner

§(?<!:|:/)/{2,}§

par BeRoots » 15 déc. 2007, 13:05

j'ai bien essayer ce que tu m'a dit mais pas moyen :?
1 (preg_match_all) : !(?<!:/?)/{2,}!
2/117 preg_match_all() [function.preg-match-all]: Unknown modifier ':'
j'ai donc essayer ceci au cas ou cela vienne des "séparateur"

Code : Tout sélectionner

§(?<!:/?)/{2,}§
j'ai plus le même message mais c'est toujour pas ça...
1 (preg_match_all) : §(?<!:/?)/{2,}§
2/117 preg_match_all() [function.preg-match-all]: Compilation failed: lookbehind assertion is not fixed length at offset 7
1°) si quelqu'un à une idée ?

j'aimerai aussi interdire la sélection de balise html en fin de chaine pour une détection d'url.
j'ai cette regex mais j'aimerai que celle-ci s'arrete avant les < pourvant ce trouver à la suite de l'url :-k
§(((file|ed2k|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(file:///)|(www\.))+(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(/[-a-zA-Z0-9&+=?#%_\./~]*)?§
voila la sélection que celle si me retourne:
2°) si quelqu'un à une idée sur comment arrêter la sélection avant le < ?