PHP-Neuling: HTML 1 Formular für EDIT und CREATE

Servus zusammen,

auch ich lerne aus meinen Fehlern und öffne daher einen neuen Thread.

Als mittiges Statement muss ich ein riesig großes Dankeschön an euch als Community aussprechen. Ohne eure Hilfe wäre ich gar nicht so weit gekommen, um jetzt diesen Thread zu öffnen :) 🌹

Nun geht es um Folgendes:

Die Site bzw. das Tool das ich hier zu bauen habe (in PHP und mysql(i)) ist von einigen Stellen abzusegnen, bevor es live geht. Nun kommen immer wieder Änderungswünsche, alá

Ach, bau doch das noch mit ein, Nimm das wieder raus, könnte man hier nicht noch dies und das, usw usw

Das ist nach dem 14. Änderungsauftrag total nervig, da ich immer wieder mein "EDIT" Formular (Das ist das Formular, dass einen gespeicherten Datensatz vollständig anzeigt und editieren lässt) sowie auch das "CREATE" Formular (...) bearbeiten muss.

Da dies auch in die Datenbank geht, habe ich schon angefangen meine Variablen und POST zuweisungen über require 'variables.php' auszulagern, sodass ich wenigstens hier nur eine zentrale Stelle habe die bearbeitet werden muss

Mein größtes Nervtum ist aber das Formular selbst mit seinen inputFeldern

im CREATE sind die input-Felder alle leer (value="")

Im EDIT sind diese natürlich nicht leer (value="<?echo php Datensatz->Wert1 ?>")

Ich habe mich auch über DOMs belesen. aber das ist harter Tobak und kam bei mir nicht so richtig an

Ich hoffe ihr habt verstanden, wo ich hin will. Kann ich !EIN! Formular bauen, welches im "Modus" EDIT die values gefüllt zeigt, und im "Modus" CREATE eben nicht?

Ich dachte schon an $_GET und im Formular dann IFfen. Also ein *.php?Modus=EDIT bzw. Modus=CREATE mitgeben, und im Formular dann für die Felder abfragen alá

<?php IF $MODUS = 'CREATE ?> ?><input xxx value=""> <?php } else { IF $MODUS = 'EDIT' ?> <input value="<?php echo Datensatz->Wert1 ?>"> <?php } ?>


Das würde sicher so funktionieren, auch für die PHP/SQL Befehle

aber irgendwie übel unübersichtlich und viel Code

Könnt ihr meinen Äußerungen folgen, und habt ihr vielleicht eine elegantere Idee für mich ?

Viele grüße, und bleibt gesund

  1. Hi,

    Mein größtes Nervtum ist aber das Formular selbst mit seinen inputFeldern

    im CREATE sind die input-Felder alle leer (value="")

    Nicht wirklich gut: es sollten die Defaults drinstehen, die in der Datenbank, oder ersatzweise in der API festgelegt wurden.

    Im EDIT sind diese natürlich nicht leer (value="<?echo php Datensatz->Wert1 ?>")

    Auch nicht vollständig: es muss passend escaped werden, also hier für den HTML-Kontext.

    Viele grüße, und bleibt gesund

    Dito
    Mitleser

    1. Nicht wirklich gut: es sollten die Defaults drinstehen, die in der Datenbank, oder ersatzweise in der API festgelegt wurden.

      was meinst du mit Defaults? Und welche Schnitstelle? PHP ist doch meine SChnittstelle?

      Ihr schafft es immer wieder sehr schnell, mich zu verwirren 😁

    2. Hallo Mitleser,

      im CREATE sind die input-Felder alle leer (value="")

      Nicht wirklich gut: es sollten die Defaults drinstehen

      Das ist jetzt Sache des Formulars und der Anforderungen, ob man Defaults in den Feldern stehen haben will.

      Aber, "Neuling", wenn Du doch das Edit-Formular aus einer $Datensatz Variablen befüllst, dann kannst du einfach einen leeren $Datensatz erzeugen und dein EDIT Formular ausgeben. Fertig ist das Erfassungsformular. Möglicherweise geht das nicht immer. Wo kommt dein $Datensatz-Objekt denn her? Ist das eine Klasse von Dir? Oder ist das ein Standardobjekt, das Du von mysqli mit fetch_object geholt hast? Kein Ding, sowas legst Du leer mit $Datensatz = new stdClass; an.

      Und dann ist deine Idee, die Du angerissen hast, völlig okay. Man kommt gelegentlich gar nicht drum herum, für CREATE und EDIT unterschiedliche Zweige zu durchlaufen. Solange es aber so aussieht wie bei Dir, geht es kompakter. Das $isEdit Flag, das ich vorneweg setze, soll Platz sparen, gerade hier im Forum ist das nützlich. Du kannst natürlich auch überall ($MODUS=="EDIT") hinschreiben.

      $isEdit = ($MODUS == "EDIT");
      
      <input name="feld1" 
             value="<?= $isEdit ? htmlspecialchars($Datensatz->Wert1) : "" ?>">
      <input name="feld2"
             value="<?= $isEdit ? htmlspecialchars($Datensatz->Wert2) : "" ?>">
      <input name="feld3" 
             value="<?= $isEdit ? htmlspecialchars($Datensatz->Wert3) : "" ?>">
      

      Das ist natürlich unvollständig, Input-Elemente brauchen auch Labels. Bei Radiobuttons oder Checkboxen musst Du passend zum Datensatzwert das checked-Attribut setzen, da ist es etwas umständlicher

      Der Unterschied zu deinem Ansatz ist nur die Schreibarbeit, nicht die Idee an sich:

      • Das Markup für das input Element steht nur einmal da, die Abfragelogik ist nur im Value-Attribut
      • <?= ... ?>, das ist die Abkürzung für <?php echo ...; ?>
      • Ich verwende den ternären Bedingungsoperator ?:. „ternär“ ist analog zu „binär“ zu sehen und heißt einfach: Operator mit drei Operanden. Man schreibt bedingung ? then-wert : else-wert. Wie die Vorrangtabelle zeigt, hat ?: eine sehr tiefe Priorität, du musst also die drei Operanden normalerweise nicht klammern.

      Die Information, ob und was Du editierst muss das Form aber auch haben. Das kannst Du im Submit-Button codieren.

         <button type="submit"
                 name="save"
                 value="<?= $isEdit ? $Datensatz->ID : "create" ?>">
            Speichern
         </button>
      

      Die ID habe ich hier nicht maskiert. Ob Du das musst, hängt davon ab, welche Werte die annehmen kann.

      Wichtig ist, dass Du die ID (oder create) auch in der Session speicherst. Wenn die Antwort vom Anwender kommt, musst Du die ID mit der geposteten ID vergleichen. Nur wenn die gleich sind, darfst Du die Antwort akzeptieren.

      Problem sind dann Anwender, die mehrere Browsertabs mit deiner Seite aufhaben und in zwei Fenstern editieren. Je nachdem, wie das Tab geöffnet wurde, ist der Sessioncookie gleich. Bei denen geht dann ein Edit schief, aber denen muss man dann erklären, dass diese Arbeitsweise nicht unterstützt wird.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. uii, jetzt kamen ja wieder massenweise Ideen rein

        Aber schön, dass meine - aufwändige - Grundidee doch nicht ganz bescheuert gewesen ist. Mit dem ternären Krams wird es etwas übersichtlicher, das habe ich nicht bedacht. Also vielleicht doch machbar

        Dennoch schaue ich mir auch die anderen Ideen nochmal an. Bevor ich für mich bewerte was besser ist, muss ich ja alles für sich erst einmal kapiert haben 😀

      2. Hi,

        im CREATE sind die input-Felder alle leer (value="")

        Nicht wirklich gut: es sollten die Defaults drinstehen

        Das ist jetzt Sache des Formulars und der Anforderungen, ob man Defaults in den Feldern stehen haben will.

        Nein, ist es nicht!

        Es ist Sache von UX und Datentransparenz, was drinzustehen hat.
        Es solltd immer der Wert drinstehen, der in def DB auch abgespeichert würde, wenn der User das Feld leer ließe!

        LG
        Mitdenker

        1. hierfür habe ich eine tabelle "template" angelegt welche als genau so ausgelesen wird wie beim EDIT in dieser table sind Standartwerte bzw. NULLen drin, sonst nix

      3. hi Rolf.

        Verständnisfrage ... Wieso muss ich dem Button klar machen, ob EDIT oder CREATE? Der soll doch bloß die Form abschicken, um den Rest kümmert sich dann der php/sql teil

          <button type="submit"
                   name="save"
                   value="<?= $isEdit ? $Datensatz->ID : "create" ?>">
              Speichern
           </button>
        

        Ich hätte das jetzt so gelöst:

        if ($MODUS == 'EDIT') {
        
        if (isset($_POST['aktion']) and $_POST['aktion']=='speichern') {
        
        
        ............................
        }}
        
        if ($MODUS == 'CREATE') {
        	
        		if (isset($_POST['aktion']) and $_POST['aktion']=='neu') {
        
        ..................
        }}
        
        
        
        <?php IF ($MODUS =='EDIT') { ?>
        <input type="hidden" name="aktion" value="speichern">
        <input id="savebutton" type="submit" value="Speichern" onclick="submit">
        
        
        <?php } else { IF ($MODUS == 'CREATE') {?>
        
        <input type="hidden" name="aktion" value="neu">
        <input id="savebuttonNEW" type="submit" value="neu" onclick="submit">
        

        funktioniert für den Zustand "neu" tatsächlich nicht aktuell. Bleibt bei weißer Seite, aber das hat evtl wiederrum andere Ursachen

        1. Hallo PHP-Neuling,

          woher hast Du den $MODUS denn, wenn das ausgefüllte Form gepostet wird?

          Rolf

          --
          sumpsi - posui - obstruxi
          1. hi den gebe ich bei der startseite mit. Beim clicken auf einen der Einträge auf der Übersichtsseite

            <a href="EDIT.php?ID=<?php echo $Datensatz->ID; ?>&MODE=EDIT">
            

            Und für das "CREATE" habe ich einen extra button mit javascript hinterlegt, da dieses Fenster im PopUp geöffnet werden soll

            <script>
            window.open("EDIT.php?MODE=CREATE", ... ");
            

            Um zu prüfen ob das $MODUS = $_GET['MODE'];

            auch wirklich funktioniert, lasse ich mir den aktuellen "Modus" auf der EDIT.php auch ausgeben

            <?php echo  "Modus: " . $MODUS ;?>
            
            1. Hallo PHP-Neuling,

              gut, wenn Du den Modus in der URL codierst, brauchst Du das im Button nicht. Aber irgendeinen value muss man ja setzen, also kann es auch "create" statt der ID des bearbeiteten Satzes sein, oder?

              Rolf

              --
              sumpsi - posui - obstruxi
              1. ich hätte zumindest gedacht, dass ich das hier getan habe

                <?php } else { IF ($MODUS == 'CREATE') {?>
                
                <input type="hidden" name="aktion" value="neu">
                <input id="savebuttonNEW" type="submit" value="neu" onclick="submit">
                

                Die Abfrage findet ja dann oben im php statt

                if ($MODUS == 'CREATE') {
                	
                		if (isset($_POST['aktion']) and $_POST['aktion']=='neu') {
                	
                	
                
                1. ich habe es nun anders gelöst, da ich das Problem mit der Form nicht beheben konnte.

                  Ich habe nun wieder 2 verschiedene Seiten die aufgerufen werden. Einmal "EDIT" und einmal "CREATE"

                  ich habe aber die komplette Tabelle ausgelagert in eine tables.php und inkludiere die nun über

                  require 'tables.php';
                  

                  Nun habe ich alle input Felder gesammelt in der tables.php und muss diese entsprechend nur noch einmal bearbeiten.

                  Die Columns werden sowieso schon aus der DB gelesen, weshalb ich diese ebenfalls nicht manuell anpassen muss

                  lediglich beim UPDATE und INSERT Befehl müssen nun noch die

                  VALUES (?, ?, ...)
                  

                  sowie die parameter

                  bind_param(ssssi...., $VAR1, $VAR2, ...)
                  

                  muss ich noch mit der Hand bearbeiten, falls Neuerungen auftreten.

                  Ich habe es leider nicht hinbekommen ein array() in's bind_param zu bringen. Das array() ist vorhanden und enthält auch alle Variablen, allerdings funktioniert es nicht (weiße Seite) wenn ich es anstelle der einzelnen Variablen einsetze

                  So ist das jetzt aber schon einmal ein guter Stand :)

                  1. Hallo PHP-Neuling,

                    Ich habe es leider nicht hinbekommen ein array() in's bind_param zu bringen. Das array() ist vorhanden und enthält auch alle Variablen, allerdings funktioniert es nicht (weiße Seite) wenn ich es anstelle der einzelnen Variablen einsetze

                    execute($dein_Array);
                    

                    Bis demnächst
                    Matthias

                    --
                    Du kannst das Projekt SELFHTML unterstützen,
                    indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                    1. mein array heißt bspw $VarUpd

                      ich müsste meinen bind_param dann so aufbauen?

                      $Eintragen->bind_param('ssi...',execute($VarUpd) );
                      
                      1. Hallo PHP-Neuling,

                        nein, ohne bindParam();, einfach execute($params);, wobei $params ein Array ist, bei dem die Parameter in der richtigen Reihenfolge vorkommen.

                        Bis demnächst
                        Matthias

                        --
                        Du kannst das Projekt SELFHTML unterstützen,
                        indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                        1. ... entsprechend müsste ich die Datentypen auch dort mit einknorkeln ? (sssi...) ? Funktioniert dann mein prepare statement noch wie gewünscht ?

                          aktuell sieht das so aus :

                          $aktualisieren = $db->prepare("UPDATE TABLE SET $ColSet WHERE ID = $ID1");
                          
                          oder eben fürs INSERT
                          
                          	$Eintragen = $db->prepare("INSERT INTO ausschreibungskalender ($ColSet) VALUES (?, ?, ?, ?, ...);
                          
                          1. Hallo PHP-Neuling,

                            nein, das kann nicht funktionieren.

                            Bis demnächst
                            Matthias

                            --
                            Du kannst das Projekt SELFHTML unterstützen,
                            indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                        2. Hallo Matthias,

                          der OP verwendet kein PDO, was man an bind_param (mysqli) statt bindParam (PDO) erkennt.

                          Übergabe der Parameterwerte als Array (mit numerischem Index für ? Marker und Keys für benannte Marker) gibt es in mysqli nicht, da muss man alles binden.

                          Rolf

                          --
                          sumpsi - posui - obstruxi
                          1. hi Rolf,

                            okay, danke für die Aufklärung :)

                            War jetzt schon wieder kurz davor (....) alles umzuschmeissen :P

  2. Tach!

    Ich hoffe ihr habt verstanden, wo ich hin will. Kann ich !EIN! Formular bauen, welches im "Modus" EDIT die values gefüllt zeigt, und im "Modus" CREATE eben nicht?

    Beim Edit hat man eine Datenstruktur mit Werten. Ein Create ist nichts anderes als ein Edit mit derselben Datenstruktur, aber mit Defaultwerten, die auch Leerstring und ähnliches sein können.

    dedlfix.

    1. hi dedlfix,

      genau so habe ich das auch verstanden. Aber wie komme ich auf die "default-werte", also quasi leerstring?

      das ist ja der Punkt, bei dem ich auf dem Schlauch stehe 🤦‍♂️

      grüße

      1. Tach!

        genau so habe ich das auch verstanden. Aber wie komme ich auf die "default-werte", also quasi leerstring?

        $record = $mode == edit ?
            fetch_object_from_db() :
            $object_with_same_structure_but_with_default_values;
        
        create_formular($record);
        

        Dem Formular muss egal sein, woher die Werte kommen. Und so kann man ihm sowohl Datenstrukturen mit Werten als auch mit Defaultwerten übergeben.

        Wenn dein Datensatz ein Objekt einer definierten Klasse ist, dann kann so ein Objekt einerseits mit Werten aus der Datenbank aber andererseits auch mit anderen (Default-)Werten gefüllt werden.

        dedlfix.

      2. hi dedlfix,

        genau so habe ich das auch verstanden. Aber wie komme ich auf die "default-werte", also quasi leerstring?

        Das wurde Dir schon vor einigen Tagen vorgeschlagen.

        das ist ja der Punkt, bei dem ich auf dem Schlauch stehe 🤦‍♂️

        Verstehe ich nicht.
        Speicherst (druckst) Du dir die Antworten auf deine Fragen nicht (aus)?

        Dokumentation ist Alles!

        LG
        Mitleser

        1. ... wenn ich mir alle Antworten hier ausgedruckt hätte, wäre ich bereits im Besitz von 14 Kurzgeschichten mit jeweils 43 Kapiteln (Warum das jetzt Kurzgeschichte heisst weiß ich auch nicht)

          ich merke schon das ich so nicht weiter komme. ich mach jetzt mal eine Stunde was anderes, und schaue mir das dann nochmal an bzgl der default werte

          $record = $mode == edit ?
             fetch_object_from_db() :
             $object_with_same_structure_but_with_default_values;
          
          create_formular($record);`
          

          für das da brauche ich einen Moment, oder vielleicht auch 4 :D

          Danke an alle :)

          Ob ihr's wollt oder nicht, ich melde mich zurück 😁

          1. Hallo,

            $record = $mode == edit ?
               fetch_object_from_db() :
               $object_with_same_structure_but_with_default_values;
            
            create_formular($record);`
            

            für das da brauche ich einen Moment, oder vielleicht auch 4 :D

            Hier wird der „ternäre Operator“ benutzt, um je nach $mode den $record zu befüllen.

            Gruß
            Kalk

      3. Hallo

        genau so habe ich das auch verstanden. Aber wie komme ich auf die "default-werte", also quasi leerstring?

        Vor der Erstellung der Ausgabe des HTML-Formulars entscheidest du doch bestimmt, ob du das leere Formular für die Neueingabe eines Datensatzes oder ein vorausgefülltes Formular für die Bearbeitung eines vorhandenen Datensatzes darstellen willst, oder?

        An der Stelle liest du doch, wenn es denn um die Bearbeitung eines Datensatzes gehen soll, auch den Selbigen aus der Datenbank. Du kannst also hernach entscheiden, was du im Formular anzeigst.

        <?php
        # Das Formular wurde für die Bearbeitung
        # eines vorhandenen Datensatzes aufgerufen
        if (isset($_POST['datensatz']) and intval($_POST['datensatz']) > 0) {
            # lies den Datensatz aus der Datenbank
            # in die Variable $dataset ein
        }
        
        # entscheide anhand der Existenz von $dataset ob ein
        # leeres oder vorausgefülltes Formular angezeigt wird
        # wie das konkret aussieht, kommt darauf an,
        # wie du den HTML-Quelltext erstellst
        ?>
        

        Du kannst jeweils einen Block für die Aufbereitung des Formulars mit oder ohne vorausgefüllten Feldern benutzen.

        <?php
        if (isset($dataset)) {
            # füge die Felder aus $dataset in die name-Attribute ein
        } else {
            # lasse die name-Attribute leer
        }
        ?>
        

        Du kannst auch ein Array erstellen, das – für egal welchen Fall – die Werte der name-Attribute enthält. Hier habe ich dafür ternäre Operatoren benutzt.

        <?php
        $nameValues['id'] = (isset($dataset['id'])) ? htmlspecialchars($dataset['id']):  '';
        $nameValues['kundenname'] = (isset($dataset['kundenname'])) ? htmlspecialchars($dataset['kundenname']):  '';
        # u.s.w.
        
        # fülle jetzt die name-Attribute im Formular
        # mit den Werten von $nameValues aus
        ?>
        

        In den Elementen von $nameValues befinden sich entweder die Werte aus dem Datensatz oder Leerstrings. Die landen so auch in den name-Attributen der Formularfelder. Die sind damit ausgefüllt oder bleiben leer.

        Zum Schluss erfolgt die Ausgabe

        <?php
        # gib das Formular aus
        echo $variableMitDemAufbereitetenQuelltextDesFormulars;
        ?>
        

        Tschö, Auge

        --
        Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
        Hohle Köpfe von Terry Pratchett
        1. Tach!

          <?php
          $nameValues['id'] = (isset($dataset['id'])) ? htmlspecialchars($dataset['id']):  '';
          $nameValues['kundenname'] = (isset($dataset['kundenname'])) ? htmlspecialchars($dataset['kundenname']):  '';
          # u.s.w.
          

          So lieber nicht. Das ist hier die Datenverarbeitung und nicht die Ausgabe. htmlspecialchars() hat hier nichts zu suchen, das muss in den Ausgabeteil, da wo das HTML erstellt wird. Dort sieht man an Ort und Stelle, dass es vorhanden ist, und muss nicht den Programmablauf rückwärts verfolgen, ob es in jedem Fall eingefügt wurde.

          Zudem verhindert solch frühzeitiges Maskieren, dass die Daten noch anderweitig verarbeitet werden können. Bei Validierungen, die zwei oder mehr Felder umfassen ist sowas zum Beispiel sehr ungünstig. Die Validierung findet üblicherweise erst nach der Prüfung auf Inhalt statt.

          dedlfix.

          1. Hallo

            <?php
            $nameValues['id'] = (isset($dataset['id'])) ? htmlspecialchars($dataset['id']):  '';
            $nameValues['kundenname'] = (isset($dataset['kundenname'])) ? htmlspecialchars($dataset['kundenname']):  '';
            # u.s.w.
            

            So lieber nicht. Das ist hier die Datenverarbeitung und nicht die Ausgabe. htmlspecialchars() hat hier nichts zu suchen, das muss in den Ausgabeteil, da wo das HTML erstellt wird. …

            Ok, gutes Argument.

            … Zudem verhindert solch frühzeitiges Maskieren, dass die Daten noch anderweitig verarbeitet werden können. Bei Validierungen, die zwei oder mehr Felder umfassen ist sowas zum Beispiel sehr ungünstig. Die Validierung findet üblicherweise erst nach der Prüfung auf Inhalt statt.

            Ich kann mir für den Fall des Lesens eines Datensatzes zur Ausgabe in einem Formular zwar keinen Fall einer nötigen Validierung vorstellen, aber sei's drum. Eine Validierung erwarte ich bei der Überprüfung einer Eingabe, also nach dem absenden eines wie auch immer ausgefüllten Formulars. Mein Beispielcode ist zudem auch kein vollständiges Beispiel. Eine eventuell dennoch nötige Validierung könnte auch zwischen dem Auslesen des Datensatzes aus der Datenbank und dem Befüllen des Arrays mit den möglichen Werten der name-Attribute stattgefunden haben, also in einem Codeabschnitt, der nicht Teil des Beispiels ist.

            Tschö, Auge

            --
            Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
            Hohle Köpfe von Terry Pratchett
            1. Tach!

              … Zudem verhindert solch frühzeitiges Maskieren, dass die Daten noch anderweitig verarbeitet werden können. Bei Validierungen, die zwei oder mehr Felder umfassen ist sowas zum Beispiel sehr ungünstig. Die Validierung findet üblicherweise erst nach der Prüfung auf Inhalt statt.

              Ich kann mir für den Fall des Lesens eines Datensatzes zur Ausgabe in einem Formular zwar keinen Fall einer nötigen Validierung vorstellen, aber sei's drum.

              Create mit leeren Feldern und Edit eines Datensatzes aus dem DBMS sind nur zwei Fälle für das Formular. Wiedervorlage der eben getätigten Eingaben (egal ob bei Create oder Edit) im Falle eines Eingabefehlers ist ein weiterer Fall, für den das Formular gerendert werden muss.

              Eine Validierung erwarte ich bei der Überprüfung einer Eingabe, also nach dem absenden eines wie auch immer ausgefüllten Formulars.

              Genau. Dann ist die Datenquelle nicht das DBMS sondern $_POST/$_GET. Damit hast du neben den Create_leer- und Edit_DBMS-Fällen noch eine weitere Stelle, wo du htmlspecialchars()-Aufrufe unterbringen musst, bevor du die Daten dem Formular zuführst.

              Mein Beispielcode ist zudem auch kein vollständiges Beispiel. Eine eventuell dennoch nötige Validierung könnte auch zwischen dem Auslesen des Datensatzes aus der Datenbank und dem Befüllen des Arrays mit den möglichen Werten der name-Attribute stattgefunden haben, also in einem Codeabschnitt, der nicht Teil des Beispiels ist.

              Dann wäre die htmlspecialchars()-Einfügung sozusagen zwischen Datenbeschaffung/-validierung und Formularausgabe. Also ein zusätzlicher Schritt, der wegfallen kann, wenn man es gleich bei der Ausgabe unterbringt.

              dedlfix.

              1. Hallo

                … Zudem verhindert solch frühzeitiges Maskieren, dass die Daten noch anderweitig verarbeitet werden können. Bei Validierungen, die zwei oder mehr Felder umfassen ist sowas zum Beispiel sehr ungünstig. Die Validierung findet üblicherweise erst nach der Prüfung auf Inhalt statt.

                Ich kann mir für den Fall des Lesens eines Datensatzes zur Ausgabe in einem Formular zwar keinen Fall einer nötigen Validierung vorstellen, aber sei's drum.

                Create mit leeren Feldern und Edit eines Datensatzes aus dem DBMS sind nur zwei Fälle für das Formular. Wiedervorlage der eben getätigten Eingaben (egal ob bei Create oder Edit) im Falle eines Eingabefehlers ist ein weiterer Fall, für den das Formular gerendert werden muss.

                Natürlich, aber den Fall habe ich in meinem Beispiel nicht berücksichtigt.

                Eine Validierung erwarte ich bei der Überprüfung einer Eingabe, also nach dem absenden eines wie auch immer ausgefüllten Formulars.

                Genau. Dann ist die Datenquelle nicht das DBMS sondern $_POST/$_GET. Damit hast du neben den Create_leer- und Edit_DBMS-Fällen noch eine weitere Stelle, wo du htmlspecialchars()-Aufrufe unterbringen musst, bevor du die Daten dem Formular zuführst.

                Natürlich, aber den Fall habe ich in meinem Beispiel nicht berücksichtigt.

                Ich hatte den Fall Wiedervorlage im Affenformular zwar schon im Hinterkopf, habe mich aber dagegen entschieden, den hier auch noch einzuführen. Der zusätzliche Fall fügte dem Beispiel zusätzliche Komplexität hinzu, die ich eher hinderlich emfände. Zudem bin ich mir nicht sicher, ob das in PHP-Neulings Fall zutrifft (habe seine anderen Threads nicht in Gänze verfolgt).

                Mein Beispielcode ist zudem auch kein vollständiges Beispiel. Eine eventuell dennoch nötige Validierung könnte auch zwischen dem Auslesen des Datensatzes aus der Datenbank und dem Befüllen des Arrays mit den möglichen Werten der name-Attribute stattgefunden haben, also in einem Codeabschnitt, der nicht Teil des Beispiels ist.

                Dann wäre die htmlspecialchars()-Einfügung sozusagen zwischen Datenbeschaffung/-validierung und Formularausgabe. Also ein zusätzlicher Schritt, der wegfallen kann, wenn man es gleich bei der Ausgabe unterbringt.

                Der Schritt ist nicht ein zusätzlicher, denn er muss so oder so gegangen werden. Es ist aber eine zusätzliche Codestelle, zu der man bei Codeüberprüfungen hinspringen muss (je nach Umfang des Codes kann das lästig sein), das wohl. Ja, mit der Unterbringung „bei der Ausgabe“ ist alles an einer Stelle, was zusammen gehört.

                Tschö, Auge

                --
                Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
                Hohle Köpfe von Terry Pratchett
  3. Ich verstehe Dich so, dass Du ein Template oder eine Funktion willst, die quasi ein- und das selbe Formular ausgibt, damit Du nicht mehrere ändern musst.

    Dafür gibt es ca. 1 Mio Möglichkeiten mit unterschiedlichen Vor- und Nachteilen - und das ist eine konservative Schätzung. Eine stell ich Dir vor.

    Du hast Die Daten optimal in einem Array:

    <?php
    $arrFormdata['id']='0815';
    $arrFormdata['foo']='Na';
    $arrFormdata['bar']='so';
    $arrFormdata['tok']='auch';
    $arrFormdata['gret']='was aber';
    ?>
    

    Dann könnte die Funktion zum Ausgeben des Formulars die fehlenden Formulardaten durch passende leere Werte ersetzen und danach das Forular mit - je nach Kontext (HTML, Input, Textarea/Button, Javascript) oder Inhalt ( → siehe intval()) entschärften(sic!) Daten ausgeben.

    function writeForm ( $caption, $arrFormdata = false ) {
    	if ( ! is_array( $arrFormdata ) ) {
    		foreach ( [ 'id', 'foo', 'bar', 'tok', 'baz', 'gret' ] as $i ) {
    			$arrFormdata[ $i ] = '';
    		}
    		 
    	}
    ?>
    <form id="<?='F_' . intval( $arrFormdata['id'] ); ?>">
        <fieldset><legend><?=htmlspecialchars( $caption );?></legend>
            <input id="id" value="<?=intval( $arrFormdata['id'] ); ?>"><br>
            <input id="foo" name="foo" value="<?=htmlspecialchars( $arrFormdata['foo'], ENT_QUOTES ); ?>" /><br>
            <textarea id="bar" name="bar"><?=htmlspecialchars( $arrFormdata['bar'] ); ?><textarea><br>
            <button id="send" name="send" onclick="say('<?=trim( json_encode( $arrFormdata['gret'] ),'"' ); ?>')"><?=htmlspecialchars( $arrFormdata['tok'] ); ?></button>
        <fieldset>
    </form>
    <?php
    }
    ?>
    

    Dann muss man die Funktion nur mit (zum Editieren) oder aber ohne Angabe des Arrays (oder mit einem leeren Wert wie false, '' statt des Arrays) aufrufen:

    <?php
    writeForm ( 'Formular mit Daten (zum Editieren)', $arrFormdata );
    writeForm ( 'Formula ohne Daten (Für neuen Datensatz)');
    

    Hier das gesamte, funktionsfähige Beispiel:

    <?php
    $arrFormdata['id']='0815';
    $arrFormdata['foo']='Na';
    $arrFormdata['bar']='so';
    $arrFormdata['tok']='auch';
    $arrFormdata['gret']='was aber';
    
    # ...
    
    writeForm ( 'Formular mit Daten (zum Editieren)', $arrFormdata );
    writeForm ( 'Formula ohne Daten (Für neuen Datensatz)');
    
    function writeForm ( $caption, $arrFormdata = false ) {
    	if ( ! is_array( $arrFormdata ) ) {
    		foreach ( [ 'id', 'foo', 'bar', 'tok', 'baz', 'gret' ] as $i ) {
    			$arrFormdata[ $i ] = '';
    		}
    		 
    	}
    ?>
    <form id="<?='F_' . intval( $arrFormdata['id'] ); ?>">
        <fieldset><legend><?=htmlspecialchars( $caption );?></legend>
            <input id="id" value="<?=intval( $arrFormdata['id'] ); ?>"><br>
            <input id="foo" name="foo" value="<?=htmlspecialchars( $arrFormdata['foo'], ENT_QUOTES ); ?>" /><br>
            <textarea id="bar" name="bar"><?=htmlspecialchars( $arrFormdata['bar'] ); ?><textarea><br>
            <button id="send" name="send" onclick="say('<?=trim( json_encode( $arrFormdata['gret'] ),'"' ); ?>')"><?=htmlspecialchars( $arrFormdata['tok'] ); ?></button>
        <fieldset>
    </form>
    <?php
    }
    ?>
    

    und der Output:

    <form id="F_815">
        <fieldset><legend>Formular mit Daten (zum Editieren)</legend>
            <input id="id" value="815"><br>
            <input id="foo" name="foo" value="Na" /><br>
            <textarea id="bar" name="bar">so<textarea><br>
            <button id="send" name="send" onclick="say('was aber')">auch</button>
        <fieldset>
    </form>
    <form id="F_0">
        <fieldset><legend>Formula ohne Daten (Für neuen Datensatz)</legend>
            <input id="id" value="0"><br>
            <input id="foo" name="foo" value="" /><br>
            <textarea id="bar" name="bar"><textarea><br>
            <button id="send" name="send" onclick="say('')"></button>
        <fieldset>
    </form>
    
    

    Man kann übrigens auch Template-Systeme benutzen. Verbreitet ist z.B. Smarty.

    1. Tach!

      Du hast Die Daten optimal in einem Array:

      Optimal für deinen Lösungsvorschlag zumindest. Objekte tun es aber auch.

      Dann könnte die Funktion zum Ausgeben des Formulars die fehlenden Formulardaten durch passende leere Werte ersetzen und danach das Forular mit - je nach Kontext (HTML, Input, Textarea/Button, Javascript) oder Inhalt ( → siehe intval()) entschärften(sic!) Daten ausgeben.

      function writeForm ( $caption, $arrFormdata = false ) {
      	if ( ! is_array( $arrFormdata ) ) {
      		foreach ( [ 'id', 'foo', 'bar', 'tok', 'baz', 'gret' ] as $i ) {
      			$arrFormdata[ $i ] = '';
      		}
      		 
      	}
      

      Mit der Schleife beschränkst du die Werte auf Leerstrings. Andere Defaultwerten, die für den Anwendungsfall eventuell auch sinnvoll sein können, sind damit nicht möglich. Man könnte die Funktion nun noch erweitern, so dass andere Defaultwerte übergeben werden. Das wird aber nur unnötig komplex.

      Zudem verlagert man die fachliche Prüfung vom Verarbeitungsteil in den Ausgabeteil. Das Beschaffen und Erzeugen der auszugebenden Werte sollte vor der Ausgabe stattfinden.

      Einfacher ist es, auf den Test ganz zu verzichten und stattdessen ein fertiges Array (in deinem Fall - oder auch ein Objekt) zu übergeben, das entweder Datenbankinhalte oder Defaultwerte enthält.

      Man kann übrigens auch Template-Systeme benutzen. Verbreitet ist z.B. Smarty.

      Die nehmen einem aber diese Arbeit nicht ab. Es kommt noch ein weiteres System dazu, dass man erlernen und beherrschen muss. Kann vorteilig in bestimmten Fällen sein, muss aber nicht. Und sie erfordern eine striktere Trennung zwischen Datenverarbeitung und Ausgabe. Defaultwerteprüfungen in Template-Engine-Syntax zu schreiben, erhöht nur die Komplexität, die man eigentlich mit der simplifizierten Template-Engine-Syntax zu verringern versucht.

      dedlfix.

      1. Zudem verlagert man die fachliche Prüfung vom Verarbeitungsteil in den Ausgabeteil. Das Beschaffen und Erzeugen der auszugebenden Werte sollte vor der Ausgabe stattfinden.

        Einfacher ist es, auf den Test ganz zu verzichten

        Du hast gesehen, wie ich writeForm() aufrufe?

        writeForm ( 'Formular mit Daten (zum Editieren)', $arrFormdata );
        writeForm ( 'Formula ohne Daten (Für neuen Datensatz)' );
        

        Demnach soll(muss!) doch das „Beschaffen der Daten“ vor der Ausgabe stattfinden.

        Was „einfacher“ ist bestimmt doch die Perspektive:

        Betrachte ich nur die (Programmierung der) Ausgabe des Formulars, dann wäre das Unterlassen der Prüfung einfacher. Betrachte ich die Sache aber aus der Perspektive der (Programmierung der) Anwendung, dann ist es (nach meinem Ermessen) einfacher, wenn (wie gezeigt) die Funktion die Prüfung macht.

        1. Tach!

          Zudem verlagert man die fachliche Prüfung vom Verarbeitungsteil in den Ausgabeteil. Das Beschaffen und Erzeugen der auszugebenden Werte sollte vor der Ausgabe stattfinden.

          Einfacher ist es, auf den Test ganz zu verzichten

          Du hast gesehen, wie ich writeForm() aufrufe?

          writeForm ( 'Formular mit Daten (zum Editieren)', $arrFormdata );
          writeForm ( 'Formula ohne Daten (Für neuen Datensatz)' );
          

          Demnach soll(muss!) doch das „Beschaffen der Daten“ vor der Ausgabe stattfinden.

          Du rufst writeForm() einmal mit und einmal ohne Daten auf. Im zweiten Fall muss sich die Funktion die Daten selbst besorgen, in deinem Falle Leerstrings und auch nur solche.

          Was „einfacher“ ist bestimmt doch die Perspektive:

          Betrachte ich nur die (Programmierung der) Ausgabe des Formulars, dann wäre das Unterlassen der Prüfung einfacher. Betrachte ich die Sache aber aus der Perspektive der (Programmierung der) Anwendung, dann ist es (nach meinem Ermessen) einfacher, wenn (wie gezeigt) die Funktion die Prüfung macht.

          Durchaus. Aber nur solange du auf Leerstrings beschränkt bleibst. Zudem ist beim Aufruf der Funktion nicht ersichtlich, dass sie sich die Defaultwerte selbst generiert. Es ist zwar mehr Code, ein Defaultwerte-Array/-Objekt explizit anzulegen, aber auch deutlicher zu sehen, woher in beiden Fällen die Daten kommen, ohne ins Innere der Funktion zu schauen. Und flexiber bei den Datentypen und Werten ist man auch noch.

          dedlfix.

  4. Hallo PHP-Neuling,

    Das ist nach dem 14. Änderungsauftrag total nervig, da ich immer wieder mein "EDIT" Formular (Das ist das Formular, dass einen gespeicherten Datensatz vollständig anzeigt und editieren lässt) sowie auch das "CREATE" Formular (...) bearbeiten muss.

    einen? oder alle/viele/einige

    Ich habe noch einen ähnlichen Lösungsvorschlag.

    $stmt = $db -> prepare("...");
    $stmt -> execute();
    $data = $stmt -> fetchAll(PDO::FETCH_ASSOC);
    
    if (count($data) == 0) : 
      // defaultwerte_holen.php');
    endif;
    

    und dort

    $stmt = $db -> prepare("SHOW COLUMNS FROM $table");
    $stmt -> execute();
    while ($row = $stmt -> fetch(PDO::FETCH_ASSOC)) :
      $data[0][$row['Field']] = $row['Default'] !== null 
        ? $row['Default'] 
        : ($row['Key'] != 'PRI' && (strpos($row['Type'],'int') !== false) || (strpos($row['Type'],'float') !== false) ? 0 : '');
    endwhile;
    

    Wenn es also default-Werte in der DB-Tabelle gibt, nimm diese, sonst setze passende Werte, hier 0 bzw. den Leerstring.

    Damit wird das array $data befüllt. Und auf diese Weise kannst du ein Formular für edit und insert verwenden.

    <?php for ($k = 0; $k < count($data); $k++) : ?>
    <label>
      Name: <input name="Name[<?=$k?>]" 
                   value="<?=htmlspecialchars($data[$k]['Name'])?>">
    </label>
    <?php endfor; ?>
    

    Bis demnächst
    Matthias

    --
    Du kannst das Projekt SELFHTML unterstützen,
    indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
    1. Tach!

      Ich habe noch einen ähnlichen Lösungsvorschlag.

      Solange das DBMS die einzige Datenquelle ist …

      $stmt = $db -> prepare("SHOW COLUMNS FROM $table");
      $stmt -> execute();
      while ($row = $stmt -> fetch(PDO::FETCH_ASSOC)) :
        $data[0][$row['Field']] = $row['Default'] !== null 
          ? $row['Default'] 
          : ($row['Key'] != 'PRI' && (strpos($row['Type'],'int') !== false) || (strpos($row['Type'],'float') !== false) ? 0 : '');
      endwhile;
      

      Eine ähnliche Prüfung muss dann noch für andere Datenquellen eingefügt werden, beispielsweise der Verarbeitung der Formulareingabwerte. Bei fachlichen Änderungen muss man somit zwei Stellen berücksichtigen.

      dedlfix.