Hilfe bei preg_match()

TTlong

Angesehenes Mitglied
Hallo,

ich möchte gern eine Textarea vernünftig validieren, hab aber irgendwo nen Fehler drin. Es werden bsp. auch Klammern, Prozentzeichen etc zugelassen, obwohl dies nicht so sein sollte.

preg_match() ist iwie nicht ganz meine Stärke.

CODE if (!preg_match('/^([\wÄÖÜäöüß\0-9\.\:\!\?\+\-\,\r\n]+)$/', trim(substr($_POST['reg_company_text'], 0, 1000)))) {
$this->message[] = $this->MsgText(9);
} else { $this->reg_company_text = $_POST['reg_company_text']; }



Zulässig sollen sein:
a-zA-Z 0-9 die Umlaute öäü und das ß
Punkt, Doppelpunkt, Plus, Minus, Komma, Fragezeichen, Ausrufezeichen, Leerzeichen, Zeilenumbruch (auch mehrere)


Wo ist der Fehler?


Mfg TTlong
 
Zunächst einmal:

Der eigentliche RegEx-Ausdruck scheint mir im wesentlichen korrekt zu sein:

\w findet nach meiner eigenen Auflistung für .NET ( http://www.sql-und-xml.de/regex/glossar.html ) die Unicode-Zeichenkategorien

QUOTE [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}]


wenn man in meiner Unicode-Datenbank nachsieht, dann gehören bsp. öffnende / schließende Klammern zu den Kategorien Ps / Pe (Punctuation, Open und Punctuation, Close), dürften also nicht dabei sein.


QUOTE (TTlong @ Di 8.06.2010, 07:34)
CODE if (!preg_match('/^([\wÄÖÜäöüß\0-9\.\:\!\?\+\-\,\r\n]+)$/', trim(substr($_POST['reg_company_text'], 0, 1000)))) {
$this->message[] = $this->MsgText(9);
} else { $this->reg_company_text = $_POST['reg_company_text']; }



Zulässig sollen sein:
a-zA-Z 0-9 die Umlaute öäü und das ß
Punkt, Doppelpunkt, Plus, Minus, Komma, Fragezeichen, Ausrufezeichen, Leerzeichen, Zeilenumbruch (auch mehrere)


Zwei Fehler fallen mir auf:


QUOTE substr($_POST['reg_company_text'], 0, 1000)


heißt, daß nur die ersten 1000 Zeichen getestet werden. Das ist nicht bloß schlecht, sondern falsch - es muß die gesamte Eingabe getestet werden. Wenn nur 1000 Zeichen zulässig sind, muß das davor geprüft werden und - unabhängig von der RegEx-Prüfung - zu einer Ablehnung führen.


CODE ^([\wÄÖÜäöüß\0-9\.\:\!\?\+\-\,\r\n]+)$


Innerhalb von .NET gibt es die Multiline-Option. Wenn die gesetzt ist, findet ^ jeden Zeilenanfang, $ jedes Zeilenende, also reicht eine korrekte Zeile, um die fehlerhaften Zeilen zu überdecken. In .NET könnte man die Multiline-Option explizit ausschalten:


CODE (?-m:^([\wÄÖÜäöüß\0-9\.\:\!\?\+\-\,\r\n]+)$)


so daß ^ wirklich den Beginn der Zeichenkette, $ das Ende findet. Ich weiß allerdings nicht, was in PHP die Voreinstellung ist.
 
Welcher Zeichensatz (iso-8859-1, iso-8859-15, utf-8)?




Ansonsten einfach mal die Dokumentation richtig lesen, PHP ist relativ gut online dokumentiert:
QUOTE [...]
By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless D modifier is set). This is the same as Perl. When this modifier is set, the "start of line" and "end of line" constructs match immediately following or immediately before any newline in the subject string, respectively, as well as at the very start and end. This is equivalent to Perl's /m modifier. If there are no "\n" characters in a subject string, or no occurrences of ^ or $ in a pattern, setting this modifier has no effect.
[...]

Quelle:

http://www.php.net/manual/en/reference.pcr...n.modifiers.php



Ohne m Option interessiert \n nicht so ganz. Daher sind ja auch Valdierungsattaken möglich, indem ein \n mit übergeben wird und danach der eigentliche Angriff kommt.



Dann sollte noch das folgende beachtet werden (wobei \w und 0-9 unsinnig ist, das 0-9 in \w drin ist..):


QUOTE \w any "word" character
\W any "non-word" character

Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair.

A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is controlled by PCRE's character tables, and may vary if locale-specific matching is taking place. For example, in the "fr" (French) locale, some character codes greater than 128 are used for accented letters, and these are matched by \w.

These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match.

The fourth use of backslash is for certain simple assertions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are

Quelle: http://www.php.net/manual/en/regexp.reference.backslash.php

Ergo hier haben wir nicht nur den ungewollten Unterstrich, sondern auch noch alle Zeichen, die nach PCRE-Tabelle zu unserer aktuell gesetzten Sprache gehören. Beim Fransösichen als Beispiel u.a. noch íáé usw.





Korrekt wäre also wohl eher:


CODE '/^[a-zA-Z0-9äöüÄÖÜß\.\:\!\?\+\-\,\r\n]+$/m'






So viel zum RegEx, aber der ein weiterer Fehler, der im Code ist, ist folgende Geschichte. Übergeben wird:
trim(substr($_POST['reg_company_text'], 0, 1000)
jeodoch wird das zugewiesen:
$_POST['reg_company_text']

Also entweder den das vor dem Prüfen durchführen:

CODE $_POST['reg_company_text'] = trim(substr($_POST['reg_company_text'], 0, 1000);


Oder die Prüfung abändern und direkt auf $_POST['reg_company_text'] prüfen:

CODE '/^\s+[a-zA-Z0-9äöüÄÖÜß\.\:\!\?\+\-\,\r\n]{0,1000}\s+$/m'





@Jürgen: Du hattest das nun, aber ich bin faul und änder den Text nicht mehr groß, ist halt Copy & Paste
wink.gif
PHP hält sich bei RegEx sehr an Perl. PCRE = Perl Compatible Regular Expressions.


PS: Gab es vorhin ein kleinen Ausfall bei Ayom?
 
QUOTE (Jürgen Auer @ Di 8.06.2010, 09:27)

...heißt, daß nur die ersten 1000 Zeichen getestet werden. Das ist nicht bloß schlecht, sondern falsch - es muß die gesamte Eingabe getestet werden. Wenn nur 1000 Zeichen zulässig sind, muß das davor geprüft werden und - unabhängig von der RegEx-Prüfung - zu einer Ablehnung führen.

Danke euch beiden. Das mit dem Prüfen der zulässigen Länge wird bereits ein IF-Konstrukt vorher geprüft, bei dem substr() geb ich dir/euch recht, es muss die gesamte Eingabe geprüft werden => mein Fehler, danke für den Hinweis.

Zeichensatz ist übrigens UTF-8



Werd mich gleich nochmal an die Doku setzen...


Thanks a lot


Mfg TTlong
 
QUOTE (TTlong @ Di 8.06.2010, 12:17) Zeichensatz ist übrigens UTF-8 [...]

Dann nimm noch die Option u dazu. Und schreibe die Umlaute lieber als Hexschreibweise (siehe \x), bzw. speichere die PHP Datei als UTF-8 ab.
 
Zurück
Oben