Fabian: Hyperlink und Mailto automatisch erkennen und ergänzen

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

  1. 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

    1. 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

  2. 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:

    • er matcht nicht auf EMail-Adressen
    • er ist unkorrekt (er matcht z. B: hallo_ich_bin_ein_esel.de)
    • er ist ineffizient

    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

    1. 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

      1. 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

        1. 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

          1. 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

            1. 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

              1. 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

              2. 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

        2. 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

          1. 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

    2. 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

      1. 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

        1. 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

          1. 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