Mathetyp: htmlentities? oder doch komplett anders?

Hallo gute Gemeinde

Eigentlich kenne ich mich nur mit html/css aus. Da mir aber die Funktionen ausgehen, beginne ich mich an php heranzutasten.

Als kleine Übungsmaßnahme habe ich mir die Aufgabe gestellt, eine ganz einfache Kommentarfunktion zu schreiben, wie es in Gästebüchern und Foren üblich ist. Hier der Quellcode:

  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">  
  
<head>  
  <!-- ... -->  
</head>  
  
<body>  
  <?php  
    $name = $_POST["name"];  
    $comments = $_POST["comments"];  
  
    if ($name=="" OR $comments=="")  
      {  
        echo "";  
      }  
    else  
      {  
        $posting = "<p>$name schrieb:</p>\n\n  <p>$comments</p>\n\n  ";  
  
        $posts = fopen("posts.txt","a");  
  
        fwrite($posts, $posting);  
  
        fclose($posts);  
      }  
  
    $give = implode("",file("posts.txt"));  
    echo $give;  
  ?>  
  
  <form action="index.php" method="post">  
  
    <label for="name">Name:</label><br />  
    <input type="text" name="name" id="name"/><br />  
  
    <label for="comments">Kommentar:</label><br />  
    <textarea name="comments" id="comments" cols="6" rows="10"></textarea><br />  
  
    <input type="submit" value="Absenden" />  
  </form>  
  
</body>  
</html>  

Das funktioniert auch soweit nur normaler Text geschrieben wird. Werden Sonderzeichen benutzt oder gar html-code, wird dieser logischerweise als solcher vom Browser interpretiert. Ich habe dann den Befehl htmlentities(); gefunden und diesen hier und da eingefügt. Das Problem ist allerdings, dass php beispielsweise " schon beim Absenden in " umwandelt. Da nützt mir das also wenig.

MfG Mathetyp

  1. Oh, meine Frage ist irgendwie abhanden gekommen:

    Kann ich das überhaupt so machen, wie ich mir das gedacht habe oder sollte ich komplett anders an die Sache heran gehen?

    MfG Mathtyp

  2. Hallo gute Gemeinde

    Hallo mein Sohn.

    Eigentlich kenne ich mich nur mit html/css aus. Da mir aber die Funktionen ausgehen, beginne ich mich an php heranzutasten.

    Was gewiss nicht immer leicht ist, vor allem, weil man es mit CGI und bösem Userinput zu tun hat.

    Als kleine Übungsmaßnahme habe ich mir die Aufgabe gestellt, eine ganz einfache Kommentarfunktion zu schreiben, wie es in Gästebüchern und Foren üblich ist. Hier der Quellcode:

    Ich kenne keine einfachen Kommentarfunktionen.
    Ich kenne leider auch kein PHP. aber das brauchen wir für den Himel eh nicht.

    [code lang=html]
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">

    <head>
      <!-- ... -->
    </head>

    <body>

    Soweit so gut. Nehm ich mal an.

    <?php
        $name = $_POST["name"];

    Hier ist das erste Problem.
    Hast du dir überlegt, dass genau diese Zuweisung eine Variable erzeugen kann, die es vorher gar nicht gab?

    in Perl müsste ich schreiben:
    if exists $post{name}{ ... }

    du müsstest wohl in PHP fargen:
    if( isset $_POST['name'] ){ ... }

    Was macht ein Browser, wenn in einem Feld kein Wert angegeben wird?
    Übertägt der Browser überhaupt den Parameter?
    Das tut er in der Regel nicht.
    Darum wird auf folgenden Anweisung:

    if ($name=="" OR $comments=="")
          {
            echo "";
          }

    Gar nicht effizient sein.

    else
          {

    Damit kommen wir zum bösen Userinput.
    Du hast da ein file vom typ txt.
    Das verwaltet records mit Daten, die ein Datensatztrennzeichen brauchen.
    Ich komme darauf zurück.

    $posting = "<p>$name schrieb:</p>\n\n  <p>$comments</p>\n\n  ";

    Das ist die schlechte variante von
      $posting = '<p>' . $name . " schrieb:</p>\n\n  <p>" . $comments . "</p>\n\n  ";

    Der Grund "text $var text" erzwingt eine Konversion einer Variable, bevor sie mit dem anderen konkateniert wird.

    $posts = fopen("posts.txt","a");

    Was geschieht wenn das File nicht geöffnet werden kann?
    wahrscheinlich sollte es heissen:
    fopen('file.txt') or die('Shit happens');

    fwrite($posts, $posting);

    Hier schreibst du deinen ungeprüften input in eine File, und jeder Poster kann dir dein File vermasseln.

    fclose($posts);
          }

    $give = implode("",file("posts.txt"));

    An diesem Punkt bemerkst du selbst, dass du in XHTML entities maskieren musst. Tue es.

    Der Rest sieht für einen Entwurf akzeptabel aus.

    echo $give;
      ?>

    mfg Beat

    --
                     /|
      <°)))o><      / |    /|
                ---- _|___/ |     ><o(((°>
               OvVVvO    __ |         ><o(((°>
    <°)))o><  /v    v\/  |
     <°)))o>< ^    ^/_/_         ><o(((°>
               ^^^^/___/
    ><o(((°>    ----       ><o(((°>
       <°)))o><                      ><o(((°>o
    1. Hallo mein Sohn.
      Ich kenne keine einfachen Kommentarfunktionen.
      Ich kenne leider auch kein PHP. aber das brauchen wir für den Himel eh

      kurze zwischenfrage: tut dir die hitze heute nicht gut? irgendwie wirkst du sehr überdreht :D

      1. Hallo mein Sohn.
        Ich kenne keine einfachen Kommentarfunktionen.
        Ich kenne leider auch kein PHP. aber das brauchen wir für den Himel eh

        kurze zwischenfrage: tut dir die hitze heute nicht gut? irgendwie wirkst du sehr überdreht :D

        Tja weisch. Bym erschte poscht, wo im Trash glandet isch, do wär y ä tyyfal gsi. Ironi heilt alle Blödsinn.

        mfg Beat

        --
                         /|
          <°)))o><      / |    /|
                    ---- _|___/ |     ><o(((°>
                   OvVVvO    __ |         ><o(((°>
        <°)))o><  /v    v\/  |
         <°)))o>< ^    ^/_/_         ><o(((°>
                   ^^^^/___/
        ><o(((°>    ----       ><o(((°>
           <°)))o><                      ><o(((°>o
        1. do wär y ä tyyfal gsi.

          der teil entzieht sich meinen schluchtenscheisser-deutschkenntnissen - bitte übersetzen ;)

          1. do wär y ä tyyfal gsi.

            der teil entzieht sich meinen schluchtenscheisser-deutschkenntnissen - bitte übersetzen ;)

            Übersetzung bitte wie im Touristendeutsch mit rauchem "ch" auszusprechen.
            ...also daa wäre ich halt ein Tüfel gewesen. Oder?

            mfg Beat

            --
               <°)))o><                      ><o(((°>o
            1. ...also daa wäre ich halt ein Tüfel gewesen. Oder?

              wenn du mir jetzt noch sagst, was ein tüfel ist ;)

              1. ...also daa wäre ich halt ein Tüfel gewesen. Oder?
                wenn du mir jetzt noch sagst, was ein tüfel ist ;)

                Du sollst deinen Herrn nicht versuchen...

                mfg Beat

                --
                   <°)))o><                      ><o(((°>o
                1. Du sollst deinen Herrn nicht versuchen...

                  wenn du damit "teufel" meinst (im übrigen sagt man hier bei uns deifi) hab ichs verstanden, allerdings ist sich google bei einer suche nach tüfel äusserst unsicher ;)

                  1. Du sollst deinen Herrn nicht versuchen...
                    wenn du damit "teufel" meinst (im übrigen sagt man hier bei uns deifi) hab ichs verstanden, allerdings ist sich google bei einer suche nach tüfel äusserst unsicher ;)

                    Tja Gott können alle buchstabieren. Seinen Arbeitgeber kennen sie leider nur als Schattenriss der sich allenthalben wie eine Mimose in jedes Detail verkriecht.
                    Ich kultiviere wohl eine ziemlich anderes Bild des Teufels, nun schon im achten Jahre, kein Dämon für eine Nacht, sondern das Grauen der Geschichte.
                    Vielleicht werde ich den Wälzer doch noch rausbringen.

                    Die Essenz meiner Arbeit findet sich jedenfalls unter dem obigen Link. So man dort sich nach 'Publikationen' und 'X-Torah' durchklicken mag.

                    mfg Beat

                    --
                       <°)))o><                      ><o(((°>o
              2. Hallo

                ...also daa wäre ich halt ein Tüfel gewesen. Oder?
                wenn du mir jetzt noch sagst, was ein tüfel ist ;)

                Pferdefuß? Sein eigener Cheffe, da rausgeschmissen? Notorischer Paktierer? Dreizack ... ach nee, das was Napoleon ... äh Neptun ...

                Tschö, Auge

                --
                Die deutschen Interessen werden am Liechtenstein verteidigt.
                Veranstaltungsdatenbank Vdb 0.2
    2. Danke. Ich hab es jetzt soweit abgeändert und jetzt kann ich auch html und php schreiben, ohne dass es explodiert. Würdest du noch etwas empfehlen?

        
        <?php  
          if(isset($_POST['name']) AND isset($_POST['comments']))  
            {  
              $name = htmlentities($_POST["name"]);  
              $comments = htmlentities($_POST["comments"]);  
        
              $posting = '<p>' . $name . " schrieb:</p>\n\n  <p>" . $comments . "</p>\n\n  ";  
        
              $posting = stripslashes($posting);  
        
              $posting = str_replace("\\\\", "\\", $posting);  
        
              $posts = fopen("posts.txt","a") or die('shit happens');  
        
              fwrite($posts, $posting);  
        
              fclose($posts);  
            }  
        
          $give = implode("",file("posts.txt"));  
        
          echo $give;  
        ?>  
      
      
      1. Nur philosophische Kommentare.
        Ich finde es eine schlechte Idee, Kommentare in konkretes HTML zu verarbeiten und zu speichern.
        Besser ist es, die Kommentar-Rohdaten geeignet zu speichern, un die Formatierung der Posts erst beim Ausdruck vorzunehmen
        Das heisst htmlentities() wird erst bei der Ausgabe fällig.
        Hingegen musst du dich an ein Datenbankformat halten, um die Rohdaten zu speichern.
        Dabei musst du aber Acht geben, dass Rohdaten die Struktur deiner Datenbank nicht zerstören.
        Die Technik ist verschieden, ob du mit SQL arbeitest, oder ob du ein CSV File selbst betreuen willst.

        mfg Beat

        --
                         /|
          <°)))o><      / |    /|
                    ---- _|___/ |     ><o(((°>
                   OvVVvO    __ |         ><o(((°>
        <°)))o><  /v    v\/  |
         <°)))o>< ^    ^/_/_         ><o(((°>
                   ^^^^/___/
        ><o(((°>    ----       ><o(((°>
           <°)))o><                      ><o(((°>o
      2. echo $begrüßung;

        <?php

        if(isset($_POST['name']) AND isset($_POST['comments']))
              {
                $name = htmlentities($_POST["name"]);
                $comments = htmlentities($_POST["comments"]);
                $posting = '<p>' . $name . " schrieb:</p>\n\n  <p>" . $comments . "</p>\n\n  ";
                $posting = stripslashes($posting);
                $posting = str_replace("\\", "\", $posting);

        $posts = fopen("posts.txt","a") or die('shit happens');
                fwrite($posts, $posting);
                fclose($posts);
              }

        $give = implode("",file("posts.txt"));
            echo $give;
          ?>

          
        
        > Würdest du noch etwas empfehlen?  
          
        Viel lernen. Gerade als Anfänger macht man selbst Fehler und stolpert über diverse PHP-Eigenheiten. Eine davon hast du schon kennengelernt, die [Magic Quotes](http://de.php.net/manual/en/security.magicquotes.php). Die sind eigentlich für Ausgaben in Datenbanken gedacht, arbeiten aber an der falschen Stelle und beeinflussen so auch die Teile eines Scripts, die keine Datenbank-Ausgaben vornehmen. Dieses Feature stirbt ab PHP 6. Am besten ist es, es auch heute schon zu deaktivieren oder seine Auswirkungen zu eliminieren: [Disabling Magic Quotes](http://de.php.net/manual/en/security.magicquotes.disabling.php).  
          
        Damit komme ich gleich zu einem nächsten Punkt. Der Übersicht ist es dienlich, wenn man sein Programm strukturiert und in die drei Teile Eingabe, Verarbeitung und Ausgabe separiert, das so genannte EVA-Prinzip. Magic Quotes beseitigen ist eine Eingabedatenbehandlung, sollte also zuerst erfolgen.  
          
        htmlentities() solltest du zu Gunsten von htmlspecialchars() wieder vergessen. HTML verlangt eine Sonderbehandlung nur für einige wenige Zeichen. Für die anderen ist es perfekt, wenn sie direkt notiert stehen und nicht als Entity oder nummerische Zeichenreferenz. Da das eine Behandlung für ein Ausgabemedium ist, kommt sie in den Ausgabe-Teil.  
          
        Es folgt meine Version des Scripts, Kommentare inklusive.  
          
          <?php  
          
        Das ist der erste Teil der Eingabebehandlung.  
          
          if (get\_magic\_quotes\_gpc()) {  
            //von verlinkter Handbuchseite nehmen  
          }  
          
        Prüfen der Eingabewerte gehört auch mit zum E-Teil. Davon abhängig ist aber der Verarbeitungsteil.  
          
          if (isset($\_POST['name']) and isset($\_POST['comments'])) {  
          
        Umkopieren in neue Variablen sollte man sich schenken, auch wenn du sie dabei gleich behandelst. Die Behandlung ist sowieso an falschen Stelle der Verarbeitungsreihenfolge, denn das wäre Aufgabe für den A-Teil.  
          
          // $name = htmlentities($\_POST["name"]);  
          // $comments = htmlentities($\_POST["comments"]);  
          
        Diese Zeilen entfallen ebenfalls, weil sie nicht (mehr) benötigt werden.  
          
          // $posting = str\_replace("\\\\", "\\", $posting);  
          // $posting = stripslashes($posting);  
          
        Jetzt kommt der V-Teil, also die Verarbeitung der Werte.  
        Ein »or die(...);« ist schnell eingefügt, aber in den wenigsten Fällen eine sinvolle Fehlerbehandlung. Zudem versaut es durch den sofortigen Gnadenschuss das Layout der restlichen Seite. Besser ist es, Fehler einzukalkulieren, sich Gedanken zu machen, was im Fehlerfall für die Anwendung gut wäre (Gibt es Alternativen? Sollte jemand über den Fehler benachrichtigt werden?) und dabei den Anwender nicht vergessen. Der sollte beispielsweise eine Tröstmeldung bekommen, mit einem Hinweis, wie er doch noch an sein Ziel kommen kann. Fehlermeldungen mit technischen Details interessieren ihn nicht. Und wenn doch, dann will man demjenigen solche Informationen nicht freiwillig preisgeben.  
          
          // $posts = fopen("posts.txt","a") or die('shit happens');  
          if ($posts = fopen('posts.txt', 'a')) {  
          
        Rohdaten zu speichern sollte man stets einer Speicherung in Ausgabeformatierung vorziehen. Somit hat man es später einfacher, das Speichermedium zu wechseln. Wenn du erst mühsam den Inhalt aus dem HTML-Code klauben musst, wenn du später mal auf eine Datenbank umsteigen möchtest, dann weißt du warum dies  
          
            //$posting = '<p>' . $name . " schrieb:</p>\n\n  <p>" . $comments . "</p>\n\n  ";  
            //fwrite($posts, $posting);  
          
        keine gute Idee war.  
          
        Wenn dir PHP ab Version 5.1.0 zur Verfügung steht - das sollte, denn PHP4 ist schon eine Weile abgekündigt - dann nimm lieber [fputcsv()](http://de.php.net/manual/en/function.fputcsv.php)  
          
            if (! fputcsv($posts, array($\_POST["name"], $\_POST['comments'])) {  
              // Fehler beim Schreiben angemessen behandeln  
            }  
            fclose($posts);  
          
        Ansonsten gibt es Nachbauten in den Userkommentaren der Handbuchseite. Diese Funktion kümmert sich darum, dass die Daten CSV-gerecht in der Daten zu stehen kommen und auch die zur Trennung der einzelnen Werte verwendeten Spezialzeichen entschärft werden, wenn diese als Datenbestandteil vorkommen.  
          
          } else {  
            // Fehler beim Öffnen/Anlegen der Datei angemessen behandeln  
          }  
          
        Gänzlich unbeachtet gelassen habe ich das Thema [Sperren von Dateien](http://aktuell.de.selfhtml.org/artikel/programmiertechnik/dateisperren/index.htm). Diese "Verkehrsampel für Programme" braucht man, damit es keine Datenunfälle gibt. Alles weitere spar ich mir, denn das steht im verlinkten Artikel. Du solltest es dir nicht sparen, wenn dir deine Daten lieb sind. Im Labor wirst du nichts bemerken, doch in freier Wildbahn greifen gelegentlich mehrere Anwender gleichzeitig zu. Da sollte der andere warten bis der eine fertig ist.  
          
        Es gibt die Funktion file\_get\_contents(), mit der man sich das unnötige Aufdröseln in Einzelzeilen durch file() und das Wiederzusammenfügen mit implode() sparen kann.  
          
            //$give = implode("",file("posts.txt"));  
          
        Doch da ich das CSV-Format vorgeschlagen habe, müssen wir dazu passende Funktionen verwenden. Wir befinden uns nun außerhalb des if(isset($\_POST[...-Bereichs. Dieser Teil wird also auch ohne eine erfolgte Eingabe ausgeführt. Das ist auch der Grund, warum ich die Datei erneut öffne und nicht das Datei-Handle gleich weiterverwende, denn im Nicht-Post-Fall ist es ja nicht gültig.  
          
          $posts\_data = array();  
          if ($posts = fopen('posts.txt', 'r') {  
            while (false !== $line\_data = fgetcsv($posts, 4000)) {  
              $posts\_data[] = $line\_data;  
            }  
            fclose($posts);  
          }  
          
        Auch hier fehlt wieder das Sperren von Dateien. Bitte selbst einbauen.  
          
        Kommen wir nun zum A(usgabe)-Teil. $posts\_data ist nun ein Array, das weitere Arrays jeweils mit Namen und Kommentar enthält. Nun erst, beim Einfügen in die Ausgabe, werden die Werte dem Ausgabekontext gemäß angepasst.  
          
          //$posting = '<p>' . $name . " schrieb:</p>\n\n  <p>" . $comments . "</p>\n\n  ";  
          foreach ($posts\_data as $post)  
            printf("<p>%s schrieb:</p>\n\n  <p>%s</p>\n\n  ",  
              htmlspecialchars($post[0]),  
              htmlspecialchars($post[1]));  
          
          ?>  
          
        printf() und die Platzhalter %s für Strings ist meiner Meinung nach der beste Kompromiss zwischen  
          echo "String mit $variable drin";  
        und Rein-in-den-String-raus-aus-dem-String-und-wieder-rein-usw.  
          echo 'String, geteilt und ' . $variable . ' extra';  
          
          
          
        echo "$verabschiedung $name";