Hyperlink und Mailto automatisch erkennen und ergänzen
Fabian
- php
Hallo liebe Forumgemeinde,
ich habe ein Formular in welches der User verschiedene Daten eingeben kann.
Die Reihenfolge der Eingaben ist undefiniert. Z.b Name, Vorname, E-mail...
Wenn man sich die Daten in einer Vorschau ansieht, würde ich gern die Hyperlinks und E-mail adressen automatisch erkennen lassen und entsprechend verlinken.
Ich denke in etwa so müßte es sein:
Hyperlink:
if (substr_count($adressenfeld_1, "www."))...ersetzte www. durch
<a href="http://www.
bei dem Ende Tag weiss ich noch nicht so recht bescheid. (Suche das erste Leerzeichen nach www. und ersetzte es durch "</a> "?)
E-Mail-Adresse:
if (substr_count($adressenfeld_1, "@"))...gehe zum ersten Leerzeichen vor @ und ersetzte es durch "<a href="mailto:" gehe dann zum ersten Leerzeichen nach @ und ersetzte es durch "</a> "
Aber wie formuliere ich das in PHP?
Vielen Dank für jegliche Tipps und Anregungen...
Grüße aus Braunschweig
Fabian
Hallo,
warum so kompliziert ?
if(eregi("www.", $string)){
echo "<a href="$string">$string</a>";
// oder in eine Var:
$string = "<a href="$string">$string</a>";
}
if(eregi("@",$string)){
// siehe oben
}
lg
Ludwig
Hallo Ludwig,
vielen Dank für deine Hilfe!
Aber was wäre, wenn der User eintippt:
"Du kannst mich auch jederzeit unter der E-Mail adresse: info@xyz.de erreichen."
Eine php Funktion habe ich gefunden, die ein Zeichen nach einem bestimmten Zeichen sucht.
z.B. das erste Leerzeichen nach dem "@"
aber an das erste Leerzeichen vor dem @ komme ich noch nicht heran.
Grüße aus Braunschweig
Fabian
Hoi,
Wenn man sich die Daten in einer Vorschau ansieht, würde ich gern
die Hyperlinks und E-mail adressen automatisch erkennen lassen und
entsprechend verlinken.
[...]
Aber wie formuliere ich das in PHP?
Das ist gar nicht so eine leichte Frage. Aus zwei Gruenden: erstens
sind RFC-gerechte URLs sehr kompliziert zu matchen. Und zweitens gibt
es da draussen im Netz leider sehr viele idiotische Programmierer, die
nicht RFC-gerechte URLs einsetzen. Man muss also einen Weg zwischen
Idealismus und Praxis finden.
Sicher ist auf jedenfall, dass du mit dem oben beschriebenen Verfahren
nicht sehr weit kommen wirst. Das Werkzeug, was du brauchst, waere
entweder ein richtiger Parser (IMHO ein fuerchterlicher Overhead in
dem Fall) oder eine RegEx, die die Ueberpruefung auf RFC-Konformitaet
annaehert. Einen solchen RegEx kannst du hier im Archiv finden, oder
auch in den Forums-Sourcen. Dass der allerdings manche Sachen (nicht
RFC-gerechte URLs, um genau zu sein) nicht schluckt, siehst du ja.
Und das er sehr kompliziert ist (im Buch ca. zwei Seiten), kommt auch
noch erschwerend dazu.
Ein beliebter Ausdruck, um URLs zu matchen, ist z. B. der
folgende (ich verwende hier PHP-Notation):
$text = preg_replace('!^(http://)?(\w+).(\w{3,5})$!',"<a href="$1$2$3">$1$2$3</a>",$text);
Der hat IMHO jedoch einige Nachteile:
Ich habe mal mich hingesetzt und einen RegEx zusammengestellt, der
IMHO in ungefaehr das liefert, was man in der Praxis so benoetigt:
$text = preg_replace('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?([A-Za-z0-9-]+.)*([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,})(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!','<a href="$1$2$3$4$5$6$7$8">$1$2$3$4$5$6$7$8</a>',$text);
Diese RegEx hat nur einen einzigen Nachteil: wenn der User kein
http:// vor die URL schreibt, dann wird leider kein Protokoll
ergaenzt. Doch das ist durch das Execute-Flag fuer den RegEx
relativ leicht auszubuegeln, ich habe nur leider kein PHP hier, mit
dem ich das pruefen koennte.
Die RegEx ist, auch wenn sie kompliziert aussehen mag, eigentlich
sehr einfach. Ich nehm sie mal stueckchenweise auseinander:
^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?
Hier wird nach einem Protokoll gesucht. Ich habe einfach mal FTP,
HTTP und Emails definiert. Wenn es eine EMail ist, wird nach dem
Usernamen geschaut.
([A-Za-z0-9-]+.)*
Hier wird nach dem ersten Teil der Domain geschaut. Der darf *nur*
aus den Zeichen A-Za-z0-9 und einem Punkt bestehen und muss
wenigstens ein Zeichen lang sein. Er *muss* aber nicht matchen
(dafuer steht das * am Ende), es kann auch sein, dass wir direkt
zu der Domain kommen (z. B. http://wwwtech.de).
([A-Za-z0-9-]{3,}.)
Hiermit definiere ich den Hauptteil der Domain. Der muss aus
wenigstens 3 Zeichen der bekannten Zeichenklasse bestehen.
([a-zA-Z0-9-]+.)*
Dem Haupt-Teil der Domain folgen weitere Teile. Sie alle muessen
aus der benannten Zeichenklasse bestehen.
([a-z]{2,})
Hiermit ist die Subdomain gemeint. Die muss aus wenigstens zwei
Zeichen bestehen.
(/[a-zA-Z%0-9.]*)*
Nun kann aber der URL auch noch ein Directory oder eine Pfad-Angabe
folgen. Diese Pfadangabe *muss* zwar nicht folgen, aber sie darf.
(?[a-z%0-9&;+=,]*)?
Der Pfadangabe darf auch noch ein Query-String folgen. Auch der ist
kein Zwang.
Jetzt ist die eigentliche Syntax-Ueberpruefung zuende. Es kann bei
URLs aber auch zu einem Anker kommen. Der Anker wiederum hat
keine Anforderungen: er darf aus beliebigen Zeichen bestehen. Deshalb
kommen wir zu
(#.*)?
So, ich hoffe, das hat jetzt geholfen.
Gruesse,
CK
Hallo Christian,
erstmal vielen Dank für deine super ausführliche Antwort.
Ich habe den Code versucht in meine Seite einzubinden und es hat auch sofort funktioniert.
Deine Antwort werde ich mir gleich ausdrucken und dann in Ruhe studieren.
Wenn ich deinen Code richtig interpretiert habe, prüft dieser in erster Linie, ob die angegebende URL auch gültig ist. (inkl. allen möglichen Facetten)
Ist das grundsätzlich überhaupt notwendig? Wenn der User bewusst eine falschen URL angibt, so hat er doch selbst schuld, dass man Ihm keine E-Mail schreiben kann, bzw. nicht auf seine Seite kommt.
Nochmals vielen Dank und die besten Grüße aus Braunschweig
Fabian
Hoi,
erstmal vielen Dank für deine super ausführliche Antwort.
Gerne
Ich habe den Code versucht in meine Seite einzubinden und es hat
auch sofort funktioniert.
Na schau ;-)
Wenn ich deinen Code richtig interpretiert habe, prüft dieser in
erster Linie, ob die angegebende URL auch gültig ist. (inkl. allen
möglichen Facetten)
Ja.
Ist das grundsätzlich überhaupt notwendig? Wenn der User bewusst
eine falschen URL angibt, so hat er doch selbst schuld, dass man
Ihm keine E-Mail schreiben kann, bzw. nicht auf seine Seite kommt.
Nun, der RegEx ist darauf ausgelegt, URLs im Fliesstext zu finden.
Und dort kann man sie nur an syntaktischer Korrektheit
identifizieren. Um den RegEx auf Fliesstext anzuwenden, musst du
allerdings noch das ^ und das $ am Anfang und am Ende entfernen.
Generell gilt aber sowieso der Grunsatz: traue keiner User-Angabe.
Damit kannst du boese auf die Schnau** fallen. Im unkritischsten
Fall koennten fehlerhafte, ungeparste Usereingaben dein Programm
zum Absturz bringen. Im schlimmsten Fall koennte ein Hacker oder
ein Scriptkiddy diese Schwachstelle in deinem Programm ausnutzen,
um Schaden anzurichten oder sich unbefugten Zutritt zu verschaffen.
Bei PHP z. B. kann es durchaus sein, dass jemand durch Usereingaben
dir die Datenbank loeschen kann.
Gruesse,
CK
Moin,
Bei PHP z. B. kann es durchaus sein, dass jemand durch Usereingaben
dir die Datenbank loeschen kann.
Entschuldige mein unqualifiziertes Reinplatzen in diesen Thread, aber _das_ will ich dann doch mal sehen.
Hast du Beweise für diese These?
PS: Der Upload-Bug für den die Patches mittlerweile überall eingespielt sein sollten zählt nicht.
--
Henryk Plötz
Grüße aus Berlin
Hoi,
Bei PHP z. B. kann es durchaus sein, dass jemand durch Usereingaben
dir die Datenbank loeschen kann.
Entschuldige mein unqualifiziertes Reinplatzen in diesen Thread,
aber _das_ will ich dann doch mal sehen.
Hast du Beweise für diese These?
Natuerlich. Aber das Bezog sich nicht auf PHP im speziellen, PHP war
nur das Beispiel, das ich herangezogen habe. Das ist natuerlich in
jeder beliebigen anderen Sprache genau dasselbe Problem. Deshalb
predige ich ja auch das grundsaetzliche validieren von User-Eingaben.
Beweis: Magic Quotes ausgeschaltet, Suchformular mit dem Feld "where".
Im Script sieht es so aus:
mysql_query("SELECT felder FROM tabelle WHERE '$where'");
User-Eingabe: abc'; DELETE FROM tabelle; SELECT 'ab
Gruesse,
CK
Moin,
Beweis: Magic Quotes ausgeschaltet, Suchformular mit dem Feld "where".
Im Script sieht es so aus:
mysql_query("SELECT felder FROM tabelle WHERE '$where'");
User-Eingabe: abc'; DELETE FROM tabelle; SELECT 'ab
Fehlermeldung: You have an error in your SQL syntax near '; DELETE FROM Forum; SELECT 'ab'' at line 1
Genau das hat irgendein schlauer Mensch verboten: Man kann in einem mysql_query-Aufruf nicht mehrere durch Semikolon getrennte Queries absenden. Abgesehen davon dass damit einige praktische Probleme weg sind (das result-set von welcher Query soll mysql_query denn dann bitteschön zurückgeben?) lösen sich die Sicherheitsprobleme damit weitgehend auf.
--
Henryk Plötz
Grüße aus Berlin
Moin,
Hallo,
das beispiel war nicht korrekt, stimmt, aber das problem besteht trotzdem, obwohl einem die php programmierer schon viel abgenommen haben.
bsp:
Eine liste mit werten aus der DB, daneben ein link um diesen eintrag zu löschen. zb. file.php?id=12&action=del
if($action=="del"){
mysql_query("DELETE FROM table WHERE id=$id");
}
was spricht nun dagegen einfach das file.php so aufzurufen:
file.php?action=del&id=(1 OR 2 OR 3 OR 4 OR 5 OR ...) (natürlich rawurlencode().ed)
noch gefährlicher wird es wenn mit like querys gearbeitet wird. ein simples % statt der ID genügt um die ganze tabelle zu löschen.
lg
Ludwig
Hoi,
Beweis: Magic Quotes ausgeschaltet, Suchformular mit dem Feld "where".
Im Script sieht es so aus:
mysql_query("SELECT felder FROM tabelle WHERE '$where'");
User-Eingabe: abc'; DELETE FROM tabelle; SELECT 'ab
Fehlermeldung: You have an error in your SQL syntax near '; DELETE
FROM Forum; SELECT 'ab'' at line 1
Genau das hat irgendein schlauer Mensch verboten: Man kann in einem
mysql_query-Aufruf nicht mehrere durch Semikolon getrennte Queries
absenden.
Das gilt fuer MySQL, ja. Aber nicht fuer andere RDBMS. Denn das
bringt durchaus auch vorteile (gesammelte INSERT-Statements, z. B.).
Abgesehen davon dass damit einige praktische Probleme weg sind
(das result-set von welcher Query soll mysql_query denn dann
bitteschön zurückgeben?)
Der letzten-
lösen sich die Sicherheitsprobleme damit weitgehend auf.
Ich glaube nicht, Tim. Auch in andererweise koennen ungeparste
Usereingaben den Programmauflauf massiv stoeren. Das solltest du
als Informatik-Student doch viel besser wissen als ich alte
Coder-Schlampe.
Gruesse,
CK
Hallo Christian,
deinen Tipp werde ich mir zu Herzen nehmen.
Die Änderungen habe ich übernommen, d.h. das ^ und nur das eine $ beseitigt was ich gefunden habe.
Komisch ist nur, dass er bei mir das "www." bei einer Domain weg läßt. Wenn ich jedoch zu Anfang http://www. scheibe, funktioniert es.
Dann werde ich jetzt mal den Execute-Flag für den RegEx suchen, damit er auch bei "www." Eingaben das http:// ergänzt.
Ich hoffe ich schaffe das... :-)
Danke und Grüße aus Braunschweig
Fabian
Hoi,
Die Änderungen habe ich übernommen, d.h. das ^ und nur das eine $
beseitigt was ich gefunden habe.
Komisch ist nur, dass er bei mir das "www." bei einer Domain weg
läßt. Wenn ich jedoch zu Anfang http://www. scheibe, funktioniert
es.
Puh, da bin ich einem Bug aufgesessen. Hier die korrigierte Version:
$text = preg_replace('!(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)*([a-zA-Z0-9.-]+.)?([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,})(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?!','<a href="$1$2$3$4$5$6$7$8">$1$2$3$4$5$6$7$8</a>',$text)
Dann werde ich jetzt mal den Execute-Flag für den RegEx suchen,
damit er auch bei "www." Eingaben das http:// ergänzt.
Viel Glueck
Ich hoffe ich schaffe das... :-)
Klaro.
Gruesse,
CK
MoiN, Christian!
Ich habe mal mich hingesetzt und einen RegEx zusammengestellt, der
IMHO in ungefaehr das liefert, was man in der Praxis so benoetigt:
$text = preg_replace('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?([A-Za-z0-9-]+.)*([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,})(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!','<a href="$1$2$3$4$5$6$7$8">$1$2$3$4$5$6$7$8</a>',$text);
Ziemlich lang, das Teil. Und leider erkennt es nicht, wenn man eine IP-Adresse eingibt, weil du fest auf das Vorhandensein von zwei oder mehr Buchstaben als TLD prüfst.
Naja, ich kommentiere mal...
^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?
Hier wird nach einem Protokoll gesucht. Ich habe einfach mal FTP,
HTTP und Emails definiert. Wenn es eine EMail ist, wird nach dem
Usernamen geschaut.
Fein. Eventuell haut dir der mailto-Teil ab, weil Usernamen eben durchaus aus mehr als nur Zeichen, Zahlen, Punkt, Unterstrich und Minus bestehen können. Irgendwie gibts auch die Variante, den Usernamen in Anführungsstrichen mit beliebigen Zeichen (auch Leerzeichen) anzugeben.
([A-Za-z0-9-]+.)*
Hier wird nach dem ersten Teil der Domain geschaut. Der darf *nur*
aus den Zeichen A-Za-z0-9 und einem Punkt bestehen und muss
wenigstens ein Zeichen lang sein. Er *muss* aber nicht matchen
(dafuer steht das * am Ende), es kann auch sein, dass wir direkt
zu der Domain kommen (z. B. http://wwwtech.de).
Wenn du den Punkt escapen würdest, würde er nicht für ein beliebiges Zeichen stehen. :)
([A-Za-z0-9-]+.)*
Und ich zähle im Geiste mit: Teil 1 plus Punkt. Beliebig häufig, und optional.
([A-Za-z0-9-]{3,}.)
Hiermit definiere ich den Hauptteil der Domain. Der muss aus
wenigstens 3 Zeichen der bekannten Zeichenklasse bestehen.
Wer behauptet, daß "Hauptteile von Domains" immer drei Zeichen lang sein müssen? Die Denic fordert heute eine Mindestlänge von drei Zeichen, es gibt aber auch 2-Zeichen-Domains wie http://www.ix.de. Und unter .com sind 2-Zeichen-Domains auch möglich (wenngleich die wohl auch alle schon registriert sind).
Geistiger Zähler: "teil1.teil1.tl2." Ein 3-Zeichen Teil zwingend.
([a-zA-Z0-9-]+.)*
Dem Haupt-Teil der Domain folgen weitere Teile. Sie alle muessen
aus der benannten Zeichenklasse bestehen.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3." Beliebig viele weitere Bestandteile, auch optional.
([a-z]{2,})
Hiermit ist die Subdomain gemeint. Die muss aus wenigstens zwei
Zeichen bestehen.
Ein 2-Zeichen-Teil zwingend.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3.de"
Tja, das Ergebnis sieht nach einer gültigen Domain aus. Mir ist zwar die Sache mit dem "Hauptteil der Domain" nicht klar, aber irgendwie wird's schon matchen.
Man kann ja sogar Zahlen nehmen:
"123.123.123.123.de" geht. Nur ist das eben keine IP-Adresse.
Minimal muß eine Domain-Angabe sowas sein: "123.de"
Der Rest (Pfad, Query, Anker) ist ja eher ungefährlich (obwohl ich beim Query-String auch Großbuchstaben zulassen würde, rein instinktiv).
Wie repariert man das jetzt? Eine zweite Verzweigungsvariante für IP-Adressen einbauen.
IP-Adressen sind so relativ leicht erkennbar:
(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})
Die Zwangslänge der Second-Level-Domain würde ich einfach auf 2 Zeichen senken (1 Zeichen ist IIRC wirklich verboten), und danach keine weiteren Bestandteile mehr zulassen, nur noch davor.
Also:
!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!
Sieht für mich irgendwie schöner aus.
Was noch fehlt: Wenn kein http-ftp-mailto angegeben wird, wird das auch nicht in den Link eingebaut. Sowas ist böse, weil es natürlich nicht funktioniert. Und das wird man kaum mit einem regulären Ausdruck durch Suchen/Ersetzen regeln können, sondern da muß weitere Programmlogik her.
preg_match ('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!',$text,$gefunden);
Im Array $gefunden stehen jetzt alle Klammerausdrücke, die der reguläre Ausdruck so produziert hat. Mit If-Abfragen und etwas Raten kann man fehlende Informationen hinzufügen und in einen schönen Link verwandeln. :)
Ich denke aber, das Thema ist noch nicht vollkommen ausdiskutiert. ;)
- Sven Rautenberg
Hallo Sven,
Ziemlich lang, das Teil. Und leider erkennt es nicht, wenn man
eine IP-Adresse eingibt, weil du fest auf das Vorhandensein von
zwei oder mehr Buchstaben als TLD prüfst.
Und den Hauptbestandteil der Domain. Es ging hier auch nicht um IPs.
^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?
Hier wird nach einem Protokoll gesucht. Ich habe einfach mal FTP,
HTTP und Emails definiert. Wenn es eine EMail ist, wird nach dem
Usernamen geschaut.
Fein. Eventuell haut dir der mailto-Teil ab, weil Usernamen eben
durchaus aus mehr als nur Zeichen, Zahlen, Punkt, Unterstrich und
Minus bestehen können.
laut RFC ja. In der Praxis eher nicht.
Irgendwie gibts auch die Variante, den Usernamen in
Anführungsstrichen mit beliebigen Zeichen (auch Leerzeichen)
anzugeben.
Ich glaube, Sven, du haettest die anderen Postings auch mal lesen
sollen ;-) Wir diskutieren hier ja nicht nur so zum Spass.
([A-Za-z0-9-]+.)*
Hier wird nach dem ersten Teil der Domain geschaut. Der darf *nur*
aus den Zeichen A-Za-z0-9 und einem Punkt bestehen und muss
wenigstens ein Zeichen lang sein. Er *muss* aber nicht matchen
(dafuer steht das * am Ende), es kann auch sein, dass wir direkt
zu der Domain kommen (z. B. http://wwwtech.de).
Wenn du den Punkt escapen würdest, würde er nicht für ein
beliebiges Zeichen stehen. :)
([A-Za-z0-9-]+.)*
Auch hier gilt: bitte die anderen Postings lesen. Der Ausdrucks-Teil
muss heissen:
([A-Za-z0-9.-]+.)*
Und ich zähle im Geiste mit: Teil 1 plus Punkt. Beliebig häufig,
und optional.
([A-Za-z0-9-]{3,}.)
Hiermit definiere ich den Hauptteil der Domain. Der muss aus
wenigstens 3 Zeichen der bekannten Zeichenklasse bestehen.
Wer behauptet, daß "Hauptteile von Domains" immer drei
Zeichen lang sein müssen?
Die gaengigen NICs
Die Denic fordert heute eine Mindestlänge von drei Zeichen,
es gibt aber auch 2-Zeichen-Domains
wie http://www.ix.de. Und unter .com sind
2-Zeichen-Domains auch möglich (wenngleich die wohl auch
alle schon registriert sind).
Stimmt, die habe ich nicht bedacht.
Geistiger Zähler: "teil1.teil1.tl2." Ein 3-Zeichen Teil zwingend.
([a-zA-Z0-9-]+.)*
Dem Haupt-Teil der Domain folgen weitere Teile. Sie alle muessen
aus der benannten Zeichenklasse bestehen.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3." Beliebig
viele weitere Bestandteile, auch optional.
([a-z]{2,})
Hiermit ist die Subdomain gemeint. Die muss aus wenigstens zwei
Zeichen bestehen.
Ein 2-Zeichen-Teil zwingend.
Geistiger Zähler: "teil1.teil1.tl2.teilweise3.teilw3.de"
Tja, das Ergebnis sieht nach einer gültigen Domain aus. Mir ist
zwar die Sache mit dem "Hauptteil der Domain" nicht klar, aber
irgendwie wird's schon matchen.
Der Hauptteil der Domain muss besondere Anforderungen erfuellen, und
er muss in *jedem* Fall vorhanden sein.
Man kann ja sogar Zahlen nehmen:
"123.123.123.123.de" geht. Nur ist das eben keine IP-Adresse.
Ja, das ist richtig. Das ist eine Schwachstelle meines RegEx.
Minimal muß eine Domain-Angabe sowas sein: "123.de"
Nein: 12a.de
Der Rest (Pfad, Query, Anker) ist ja eher ungefährlich
Noe, wenn schon validieren, dann richtig validieren.
(obwohl ich beim Query-String auch Großbuchstaben zulassen würde, »» rein instinktiv).
Jap. Ein Fehler. Ich sollte mehr schlafen, die letzte Nacht habe ich
gar nicht geschlafen.
Wie repariert man das jetzt? Eine zweite Verzweigungsvariante für
IP-Adressen einbauen.
IP-Adressen sind so relativ leicht erkennbar:
(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})
So validierst du allerdings keine IP-Adressen.
Die Zwangslänge der Second-Level-Domain würde ich einfach auf 2
Zeichen senken (1 Zeichen ist IIRC wirklich verboten), und danach
keine weiteren Bestandteile mehr zulassen, nur noch davor.
Also:
!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!
Sieht für mich irgendwie schöner aus.
Was noch fehlt: Wenn kein http-ftp-mailto angegeben wird, wird das
auch nicht in den Link eingebaut.
Habe ich ja geschrieben. Das kann man sehr einfach ueber /e einbauen.
Ich habs nur einfach nicht getan, damit Martin auch noch denkt. In
meiner Perl-Version ist das natuerlich eingebaut ;-)
Sowas ist böse, weil es natürlich nicht funktioniert.
Und das wird man kaum mit einem regulären Ausdruck durch
Suchen/Ersetzen regeln können, sondern da muß weitere
Programmlogik her.
Noe.
preg_match ('!^(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})|([A-Za-z0-9-]+.)*([A-Za-z0-9-]{2,}.)([a-z]{2,}))(/[a-zA-Z%0-9]*)*(?[a-z%0-9&;+=,]*)?(#.*)?$!',$text,$gefunden);
Der RegEx ist Buggy, wegen des |.
Im Array $gefunden stehen jetzt alle Klammerausdrücke, die der
reguläre Ausdruck so produziert hat. Mit If-Abfragen und etwas
Raten kann man fehlende Informationen hinzufügen und in einen
schönen Link verwandeln. :)
Iwo. Das geht mit einem RegEx.
Also, meine debuggte Version:
preg_replace('!(:?(:?(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)*([a-zA-Z0-9.-]+.)?([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,}))|(:?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})))(/[a-zA-Z%0-9]*)*(?[a-zA-Z%0-9&;+=,]*)?(#.*)?!e','"<a href="".("$6" ? "$6" : (($1 ? "$1" : 'http://)."$2$3$4$5")."$7$8$9">$1$2$3$4$5$6$7$8</a>"',$text)
Das ist leider ungetestet und koennte kleinere Fehler im e-Teil
haben.
Gruesse,
C'Klammerkoenig'K
MoiN, Christian!
Ich glaube, Sven, du haettest die anderen Postings auch mal lesen
sollen ;-) Wir diskutieren hier ja nicht nur so zum Spass.
Hatte ich gelesen. :)
Im Array $gefunden stehen jetzt alle Klammerausdrücke, die der
reguläre Ausdruck so produziert hat. Mit If-Abfragen und etwas
Raten kann man fehlende Informationen hinzufügen und in einen
schönen Link verwandeln. :)
Iwo. Das geht mit einem RegEx.
Also, meine debuggte Version:
preg_replace('!(:?(:?(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)*([a-zA-Z0-9.-]+.)?([A-Za-z0-9-]{3,}.)([a-zA-Z0-9-]+.)*([a-z]{2,}))|(:?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})))(/[a-zA-Z%0-9]*)*(?[a-zA-Z%0-9&;+=,]*)?(#.*)?!e','"<a href="".("$6" ? "$6" : (($1 ? "$1" : 'http://)."$2$3$4$5")."$7$8$9">$1$2$3$4$5$6$7$8</a>"',$text)
Das ist leider ungetestet und koennte kleinere Fehler im e-Teil
haben.
Hat es auch gehabt. Als Belohnung für die Trickkiste gibts jetzt eine debuggte und getestete Version, die wirklich hervorragende Dienste leistet (war ja auch sehr gute Vorarbeit).
Da ich Befürchtungen habe, daß das Forum den extrem langen RegExp zerhackt und unbrauchbar macht, zerteile ich die Zeile in handliche Stückchen.
$pattern = '!(:?(:?(http://|ftp://|mailto:[a-zA-Z0-9._-]+@)*';
$pattern .= '([a-zA-Z0-9.-]+.)?([A-Za-z0-9-]{2,}.)([a-zA-Z0-9-]+.)*';
$pattern .= '([a-z]{2,}))|(:?((\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})))';
$pattern .= '(/[a-zA-Z%0-9]*)*(?[a-zA-Z%0-9&;+=,]*)?)(#.*)?!e';
$ersatz = '"<a href="".("$6" ? "$6" : (("$3" ? "$3" : "http://")';
$ersatz .= '."$4$5"))."$7$8$9">$3$4$5$6$7$8</a>"';
Wenn dann in $text der zu ersetzende Text steht, kriegen eingegebene Links so einen HTML-Link drauf.
Zum Testen:
$text = "Link zu forum.de.selfhtml.org! Bitte auch bei http://selfaktuell.teamone.de vorbeischauen. Dumm: Das gibt Fehler.aber sowas passiert eben.";
$neutext = preg_replace($pattern,$ersatz,$text);
echo htmlentities($neutext)."<br>\n";
echo "$neutext<br>\n";ergibt
Ausgabe:
Link zu <a href="http://forum.de.selfhtml.org">forum.de.selfhtml.org</a>! Bitte auch bei <a href="http:// selfaktuell.teamone.de">http://selfaktuell.teamone.de</a> vorbeischauen. Dumm: Das gibt <a href="http:// Fehler.aber">Fehler.aber</a> sowas passiert eben.
Link zu <forum.de.selfhtml.org>! Bitte auch bei <http:// selfaktuell.teamone.de> vorbeischauen. Dumm: Das gibt <Fehler.aber> sowas passiert eben.
Gruesse,
C'Klammerkoenig'K
Wahrlich mit dem Klammerbeutel gepudert. ;)
- Sven Rautenberg
Hoi Sven,
Ich glaube, Sven, du haettest die anderen Postings auch mal lesen
sollen ;-) Wir diskutieren hier ja nicht nur so zum Spass.
Hatte ich gelesen. :)
Und trotzdem mit meiner buggy Version weiter gearbeitet? Ts,
ts, ts ;-)
Hat es auch gehabt. Als Belohnung für die Trickkiste gibts jetzt
eine debuggte und getestete Version, die wirklich hervorragende
Dienste leistet (war ja auch sehr gute Vorarbeit).
War mir klar. Ich hab halt kein PHP zum testen hier...
Gruesse,
CK, diesmal ausgeschlafen