2010-08-31 26 views
2

Je suis en train de créer un moteur d'analyse bbcode et j'ai rencontré une situation que je n'arrive pas à résoudre par moi-même.L'expression régulière se bloque Apache en raison des limitations de PCRE

La chose est que je sauté dans un problème exactement comme celui-ci: Apache/PHP on Windows crashes with regular expression

Cela signifie que si je fais quelque chose comme l'exemple ci-dessous Apache tombe en panne à cause du nombre de récursion atteignant 690 (limite de mémoire 1Mo pour PCRE):

$txt = '[b]'.str_repeat('a', 338).'[/b]'; // if I change repeat count to lower value it's ok 
$regex = '#\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))](?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)\[/(?P=tag)]#mi'; 

echo preg_replace_callback($regex, function($matches) { return $matches['content']; }, $txt); 

Je dois donc en quelque sorte de minimiser la nécessité de * et + dans mon regex, mais c'est là où je suis d'idées, donc je si vous peut-être pourrais suggérer quelque chose.

D'autres approches pour l'analyse de bbcode (qui pourraient gérer les balises imbriquées) sont les bienvenues. Cependant, je ne voudrais pas utiliser une classe déjà construite ou quelque chose. J'aime faire les choses par moi-même!

J'ai également examiné PECL et Pear HTML_BBCodeParser. Mais je ne veux pas que mon application dépende des extensions. Plus probablement je peux faire un script qui vérifie cette extension et si elle n'existe pas, utilisez l'analyseur BBCode que j'essaye de faire ici.

Désolé si mes descriptions sont sombres, je ne suis pas pro à l'anglais ^^

EDIT. Donc, l'expression régulière a expliqué:

\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))] 

Ceci est ma balise d'ouverture. J'ai utilisé des groupes nommés. Avec 'tag' j'identifie tag et avec 'attributs' j'identifie les attributs tags. Pensez à tag comme un attribut aussi. Alors qu'est-ce qui se passe ici? J'essaie de faire correspondre une étiquette, quand une étiquette est appariée, j'essaie de faire correspondre n'importe quoi après = signe ou quoi que ce soit après \s (spacer) jusqu'à ce qu'il atteigne la fermeture de l'étiquette ].

(?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?) 

Maintenant, j'essaie de faire correspondre le contenu. C'est la partie difficile. Je suis à la recherche de tout caractère non [et si je trouve tout, puis-je vérifier si ce n'est pas mon tag fin ou récursion, et je dis le moteur de regex de le faire jusqu'à ce que ....

\[/(?P=tag)] 

... la balise de fin est trouvée.

+2

- Je dirais que cette option est loin «J'ai également examiné PECL et poire HTML_BBCodeParser Mais je ne veux pas que ma demande soit en fonction des extensions. » plus préférable de réinventer la roue. –

+2

'J'aime faire les choses par moi-même! '- Pourquoi est-ce? Est-ce que tu écris aussi ton propre moteur d'expression régulière? Ou votre propre interpréteur php/runtime? – VolkerK

+0

Btw: Vous pouvez répartir votre code d'expression régulière sur plusieurs lignes et expliquer les parties avec des commentaires. Je pense que cela peut améliorer vos chances d'obtenir de l'aide. – VolkerK

Répondre

2

Je voulais vous proposer un BBCodeParser ...

J'ai aussi examiné PECL et poire HTML_BBCodeParser. Mais je ne veux pas que mon application dépende des extensions

Je trouve cela très étrange. Pourquoi réinventer la roue? L'un des principes de la bonne ingénierie logicielle est DRY (Do not Repeat Yourself). Vous essayez de résoudre un problème qui a déjà été résolu.

J'aime faire des choses par moi-même!

Ce n'est pas mauvais en soi, mais il y a des fois où il vaut mieux utiliser une solution éprouvée; celui qui est mieux testé et plus robuste que le vôtre (comme vous le découvrez).De cette façon, vous passerez du temps sur le problème que vous voulez réellement résoudre au lieu de résoudre un problème qui a déjà été résolu. Ne tombez pas dans le piège de réinventer la roue. :)

Ma suggestion (et solution) à vous est d'utiliser un analyseur BBCode.

EDIT

Une autre chose est que vous l'analyse syntaxique quelque chose qui est HTML semblable. Les choses de cette nature ne se prêtent pas facilement à être analysées par des expressions régulières.

+0

Eh bien, je parlais du côté serveur (je veux dire qu'il doit être installé par l'hébergeur ou l'administrateur du serveur) des extensions que suggère php.net. Il est toujours préférable d'avoir une application autonome que vous pouvez simplement télécharger sur l'hôte et elle est prête à l'emploi. – Paul

+0

Cela devrait être un commentaire car il ne répond pas à la question OP. – Artefacto

+0

Je suppose que vous avez manqué cette partie: "Ma suggestion (et solution) à vous est d'utiliser un analyseur BBCode.", Et la partie après la modification. –

3

Votre expression régulière, en particulier les assertions de largeur nulle (lookaround) provoquent un retour en arrière catastrophique du moteur regex. Morale de l'histoire: Regex ne peut pas ne devrait pas être utilisé pour analyser les langues qui ne sont pas régulières. Si vous avez des structures imbriquées, ce n'est pas un langage régulier.

En fait, je pense que le BBCode est mal. Le BBCode est un langage de balisage inventé par des programmeurs fainéants qui ne voulaient pas filtrer correctement le HTML. En conséquence, nous avons maintenant une «norme» lâche qui est difficile à mettre en œuvre. Filtrez votre HTML la bonne façon:

http://htmlpurifier.org/

+0

Hmm ... Peut-être que vous avez raison d'utiliser regex pour un tel sujet. Eh bien HTML au lieu de BBCode serait génial, mais les gens sont habitués à BBCode et c'est comme une sorte de standart maintenant si vous ne pouvez pas le jeter. – Paul