Werner: Fehler in Formularen

Hallo,

ich habe eine kleine Webapplikation, in der umfangreiche vom Besucher einzugebende Daten in eine Datenbank geschrieben werden. Die Formularskripte lesen jeweils die Werte aus den Datenbanken aus und geben sie in den Eingabefeldern aus. Nach Absenden eines Formulars werden die neuen Eingaben in die Datenbank geschrieben und sodann wieder der Teil durchlaufen, der schon anfangs die Daten aus der Datenbank ausgelesen hat, und die aktualisierten Daten ausgegeben.

Soweit funktioniert das gut, solange die neuen Eingaben korrekt sind. Treten Fehler auf, funktioniert das Verfahren nicht mehr, wenn die fehlerhaften Daten ausgegeben werden sollen. Im Moment habe ich es (vorläufig) so gemacht, daß geprüft wird, ob die Eingaben richtig sind. Ist nur eine Eingabe falsch, werden der gesamte Request zurückgewiesen, also nichts in die Datenbank geschrieben, und die alten Daten aus der Datenbank ausgegeben.

Das ist natürlich noch nicht das, wie es im Endeffekt einmal sein soll. Ich habe das vorläufig nur so, weil ich noch nicht weiß, was der Endzustand sein soll. Ich habe folgende Möglichkeit ins Auge gefaßt, die ich so auch mal in einem CMS verwirklicht hatte:

1. Prüfung, ob Benutzereingaben korrekt sind.

2. Ja => Daten in Datenbank schreiben und entweder (neue) Daten noch einmal aus Datenbank auslesen und ausgeben (= unnötige Belastung der Datenbank), oder Unterscheidung, ob Formular erstmals aufgerufen, dann Daten aus Datenbank auslesen und ausgeben, sonst Requestdaten ausgeben. Nein => Fehlermeldung, was falsch ist, und fehlerhafte Requestdaten in die Eingabefelder schreiben.

3. Für den Fall falscher Benutzereingaben: In den Eingabefeldern stehen die falschen Benutzereingaben. Sie wurden nicht in der Datenbank gespeichert. Deswegen ein Button, der "resettet", indem die in der Datenbank gespeicherten gültigen Werte ausgelesen und ausgegeben werden.

Fragen:

1. Was haltet Ihr von diesem Verfahren?
2. Sollte ich alle Fehlermeldungen am Kopf des Formulars ausgeben oder eher bei jedem einzelnen Eingabefeld, worin fehlerhafte Daten sind, was ich besser finde? Wie kann man das zweite am besten realisieren, ohne bei jedem Eingabefeld eine IF-Abfrage formulieren zu müssen? Im Moment ist im Kopf der Skripte der PHP-Teil, der dann abgeschlossen wird und in reine HTML-Ausgaben mündet, die nur von den Datenbankausgaben durchbrochen werden, was so aussieht:

<?php Prüfungen usw. ?>

...

<input type="text" name="plz" value="<?= $datensatz["plz"]?>">
<input type="text" name="ort" value="<?= $datensatz["ort"]?>">

Wenn ein Fehler auftritt und dies beim zugehörigen Feld ausgegeben werden soll

z. B. so

<input type="text" name="plz" value="abc" class="fehler"> Sie haben eine ungültige PLZ eingegeben. Diese muß numerisch sein.

gefällt mir diese (vereinfachte) Variante

<input type="text" name="plz" value="?= $datensatz["plz"] oder $_POST[="plz"]?>" <?php if ($fehler=="...") echo 'class="fehler"'?>><?php if ($fehler=="...") echo 'Sie haben eine ungültige PLZ eingegeben. Diese muß numerisch sein.'?>

nicht allzu gut, weil das kaum noch zu lesen ist.

Besser wäre meines Erachtens sowas

<input type="text" name="plz" value="?= $datensatz["plz"] oder $_POST[="plz"]?>{FEHLERKLASSE}>{FEHLERMELDUNG}

Doch wie realisiere ich das am besten? Die HTML-Ausgaben in einem String sammeln und mittels regulärer Ausdrücke {FEHLERKLASSE} und {FEHLERMELDUNG} ersetzen? Kann ich nicht auch in einem reinem HTML-Teil, die Platzhalter ersetzen?

  1. nicht allzu gut, weil das kaum noch zu lesen ist.

    Doch wie realisiere ich das am besten? Die HTML-Ausgaben in einem String sammeln und mittels regulärer Ausdrücke {FEHLERKLASSE} und {FEHLERMELDUNG} ersetzen? Kann ich nicht auch in einem reinem HTML-Teil, die Platzhalter ersetzen?

    Um nur erst einmal die Frage der Lesbarkeit zu beantworten, solltest Du vielleicht die Verwendung der heredoc Syntax in Erwägung ziehen - damit kannst Du Dir die ständigen <?php echo ... >? Tags sparen.

    Ich sehe nicht, wie Dir reguläre Ausdrücke hier helfen sollten...

    1. nicht allzu gut, weil das kaum noch zu lesen ist.

      Doch wie realisiere ich das am besten? Die HTML-Ausgaben in einem String sammeln und mittels regulärer Ausdrücke {FEHLERKLASSE} und {FEHLERMELDUNG} ersetzen? Kann ich nicht auch in einem reinem HTML-Teil, die Platzhalter ersetzen?

      Um nur erst einmal die Frage der Lesbarkeit zu beantworten, solltest Du vielleicht die Verwendung der heredoc Syntax in Erwägung ziehen - damit kannst Du Dir die ständigen <?php echo ... >? Tags sparen.

      Ich sehe nicht, wie Dir reguläre Ausdrücke hier helfen sollten...

      Ja, heredoc sagt mir was. Ich war bisher der Meinung, eine Seite wird schneller geladen, wenn man darauf verzichtet, weil in dem Fall der reine HTML-Teil nicht geparst werden muß.

      Reguläre Ausdrücke würden funktionieren, wenn ich die HTML-Ausgaben in einen String setze

      $html "<body> ... <input ... >{FEHLER} ... </body>";

      echo $html;

      Dann kann man den Platzhalter leicht austauschen. Hätte aber den gleichen Nachteil wie heredoc, daß es geparst wird.

  2. Hello,

    C  Erstaufruf
    S  Session aufbauen
    S  Zertifikat vorhanden?

    S  Für das Formular ein Zertifikat auswürfeln
    S  Für das Formular unter dem Zertifikat einen leeren "Record" in der Session ablegen
    S  Defaults aus der Datenbank-Definition auslesen
    S  Formulardaten aufbauen aus der Session
    S  altes Zertifikat "ungültig" kennzeichnen, wenn vorhanden (alten Datenblock ggf, löschen)
    S  Formulardaten senden

    C  Formular anzeigen, ausfüllen und absenden

    S  Für das Formular ein Zertifikat auswürfeln
    S  Formulardaten prüfen und in Session eintragen
    S  Fehlermeldungen aufbauen und in die Session eintragen
    S  Formulardaten aufbauen aus der Session
    S  altes Zertifikat "ungültig" kennzeichnen, wenn vorhanden (alten Datenblock ggf, löschen)
    S  Formulardaten senden

    C  Fehlermeldungen anzeigen
    C  Formular anzeigen, ausfüllen und absenden

    ...

    Und so geht das ewig weiter, bis keine Fehlermeldungen mehr vorhanden sind.
    Wenn ein Request ohne gültiges Zertifikat kommt, ist es z.B. ein Erstaufruf, ein Fehler oder ein Fake...

    Harzliche Grüße vom Berg
    http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau

    1. Hello,

      C  Erstaufruf
      S  Session aufbauen

      Da bin ich nicht drauf eingegangen, aber es läuft über Sessions.

      S  Zertifikat vorhanden?

      S  Für das Formular ein Zertifikat auswürfeln

      Was meinst Du damit? Eine Zufallszahl bei jedem Seitenaufruf generieren und als Variable in der Session speichern ($_SESSION["zertifikat"] = ...)? if (!isset($_SESSION["zertifikat"])) => Erstaufruf oder Fake?

      S  Für das Formular unter dem Zertifikat einen leeren "Record" in der Session ablegen

      Verstehe ich auch nicht.

      Also keine Möglichkeit für den Besucher vorsehen, die fehlerhaften Eingaben mit den Daten aus der Datenbank zu überschreiben?

      1. Hello,

        Verstehe ich auch nicht.

        Ist auch nicht so einfach´zu verstehen.

        Datenaustausch mit dem Client grundsätzlich nur über die Session.
        Das bedeutet also, dass alle Ausgaben an die Session stattfinden.
        Erst, wenn eine Funktion entscheidet, jetzt müsste der Client informiert werden, ruft man die HTML-Ausgabe-Funktion des Dokument-Generators auf (den baust Du Dir ja schließlich gerade).
        Der weiß dann, wo welcher Datenblock, welche Fehlermeldungen, welche Buttons hingehören, holt sich deren Eigenschaften aus der Session (ggf. auch ein false wegen "!isset()" ) und veranlasst dann die Ausgabe an die Standardausgabe (Browser) und ein Exit.

        So hat man immer eine valide HTML-Ausgabe.
        Außerdem gibt man dem Formular so immer ein unverbrauchtes Zertifikat mit, an dem der Server später erkennen kann, ob dieses Formular bereits verarbeitet wurde, oder ggf. auch reentrant angefordert wurde, was meistens nicht sein soll. Um sich die Daten aber nicht kaputtzuschreiben, muss man bei erkannter Reentranz (es kommt zu dem Formular, obwohl es noch nicht verarbeitet war, eine weiterer Request) darauf entsprechend reagieren.

        Harzliche Grüße vom Berg
        http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau

        1. Hello,

          Verstehe ich auch nicht.

          Ist auch nicht so einfach´zu verstehen.

          Datenaustausch mit dem Client grundsätzlich nur über die Session.
          Das bedeutet also, dass alle Ausgaben an die Session stattfinden.

          So habe ich das ja auch schon.

          Erst, wenn eine Funktion entscheidet, jetzt müsste der Client informiert werden, ruft man die HTML-Ausgabe-Funktion des Dokument-Generators auf (den baust Du Dir ja schließlich gerade).
          Der weiß dann, wo welcher Datenblock, welche Fehlermeldungen, welche Buttons hingehören, holt sich deren Eigenschaften aus der Session (ggf. auch ein false wegen "!isset()" ) und veranlasst dann die Ausgabe an die Standardausgabe (Browser) und ein Exit.

          So hat man immer eine valide HTML-Ausgabe.
          Außerdem gibt man dem Formular so immer ein unverbrauchtes Zertifikat mit, an dem der Server später erkennen kann, ob dieses Formular bereits verarbeitet wurde, oder ggf. auch reentrant angefordert wurde, was meistens nicht sein soll. Um sich die Daten aber nicht kaputtzuschreiben, muss man bei erkannter Reentranz (es kommt zu dem Formular, obwohl es noch nicht verarbeitet war, eine weiterer Request) darauf entsprechend reagieren.

          Du meinst mit Zertifikat das, was hier http://www.php-faq.de/q/q-scripte-abstimmung.html als Challenge beschrieben wird?

          Harzliche Grüße vom Berg
          http://www.annerschbarrich.de

          Tom

          Soweit ist mir das ja schon klar. Meine eigentlichen Fragen waren aber erstens, ob es sinnvoll ist, dem Benutzer eine Möglichkeit zu geben, seine fehlerhaften Eingaben zu verwerfen, indem die Daten aus der Datenbank ausgelesen und ausgegeben werden, und zweitens, wie ich am einfachsten Fehlermeldungen direkt bei den betroffenen Eingabefeldern verwirklichen kann. Gerade bei dem zweiten habe ich programmiertechnisch keine Ahnung, wie das zu realisieren ist. Das erste ist eher eine Frage der Usability.

  3. Vielleicht habe ich mein Problem nicht deutlich genug beschrieben.

    Für das Problem, wie ich am besten Fehlermeldungen bei den Eingabefeldern ausgebe, ohne die Lesbarkeit allzu sehr zu zerstören, habe ich mir inzwischen eine Lösung einfallen lassen.

    Bleibt die Frage nach der Ausgabe fehlerhafter Eingaben. Hoffentlich kann ich es anhand eines Beispiels verdeutlichen. Beim ersten Aufruf der Seite wird der Wert aus der Spalte "plz" aus der Datenbank geholt und ausgegeben:

    <input type="text" name="plz" value="10000">

    Der Benutzer gibt versehentlich einen falschen Wert 15ooo (das sind nach 15 keine Nullen) ein. Die Überprüfung stellt das fest, und es wird

    <input type="text" name="plz" value="15ooo"> Sie haben eine ungültige PLZ eingegeben.

    ausgegeben.

    Wenn der Benutzer "plz" leer absendet, würde value="" lauten. Ich frage mich, ob es dann nicht sinnvoller ist, den Default-Wert "10000" aus der Datenbank auszugeben, oder zumindest einen Link anzubieten, der die Default-Werte aus der Datenbank in die Eingabefelder einträgt. Deutlicher wird das Problem bei einem Textarea-Feld, in dem schon viel Text stand. Durch irgend einen "Unfall" könnte der Benutzer den Eintrag gelöscht haben und eine leere Eingabe absenden. Er würde auf seinen Fehler hingewiesen werden und eine leere Textarea vorgesetzt bekommen. Natürlich wird er sich nicht darin erinnern können, was darin stand. Will er es also wiederherstellen, muß er die Seite verlassen und wieder neu aufrufen, um die Default-Werte aus der Datenbank angezeigt zu bekommen.

    Hat denn keiner einen Vorschlag, wie man das am besten und vor allem benutzerfreundlichsten macht? Mit dem Problem hat doch im Prinzp jeder zu tun, der etwas aufwendigere Formulare anbietet, deren Einsatzzweck Veränderungen vorhandener Datensätze sind. Ich habe, ehrlich gesagt, noch nie darauf geachtet, wie das andere Websites handhaben.