Johann: PHP-Aufbau Formular

Hi,

bin PHP Neuling und noch auf der Suche nach einem geeigneten Templateaufbau.

Bei meinem Versuch ein Formular auf Eingaben zu prüfen erscheint statt dem Formular nur mein Quelltext.
Ich versuch mal den für mich komplexen Aufbau darzustellen.

Habe eine index.php, die sich ein Template lädt und die Platzhalter des Templates mit preg_replace ersetzt.

Um den Platzhalter "content" zu füllen, rufe ich meine getContent-Funktion auf, die den benötigten Content zurückgibt.

Den benötigten Content hole ich mir (in der getContent-Funktion) mit file_get_contents(check.php), wobei die Datei check.php ein Formular auf korrekte Eingaben prüft.

Die check.php bekommt das Formular mit include 'formular.txt', die nur eine <form> enthält.

<form action="check.php" method="post" enctype="multipart/form-data">

Hoffe es ist einigermaßen verständlich und jemand kann mir weiterhelfen.

Grüße
Johann

  1. Hello,

    Du hast auf jeden Fall schon einen Plan.
    Der klingt ganz gut.

    Allerdings habe ich nicht verstanden, was da noch Deine Frage ist.
    Kannst Du die noch mal etwas genauer formulieren?

    Liebe Grüße aus Syburg bei Dortmund

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hallo Tom,

      mein Problem ist, dass in der index.php nicht mein Formular angezeigt wird, sondern fast der gesamte Quelltext von der check.php.
      Ich hatte schon mal einen anderen Aufbau, da hat die check.php funktioniert.
      Darum war meine Vermutung, dass etwas am neuen Aufbau nicht passt.

      Oder woran könnte es sonst liegen?

      Johann

      1. Darum war meine Vermutung, dass etwas am neuen Aufbau nicht passt.

        deine templateengine muss den php code evaluieren und dann erst zusammensetzen - file_get_contents() liest den inhalt, aber jagt ihn nicht mehr durch den php-interpreter

        das ist üblicherweise der heikle punkt an einer templateengine

        du hast einerseits den php-code der ausgeführt werden soll und andererseits das html, in welches das ganze eingekleidet werden soll

        die frage ist, ob du nun mit dem php-code das html holst oder mit einem script den php-code und das html-zeug holst und dort beides zusammenfügst

        prinzipiell ist php ansich als "templateengine" gedacht gewesen, weshalb erster variante näher liegt - nachdem sich php aber zunehmend zur objektorientierten programmiersprache hinentwickelt, ist zweitere lösung schon wieder fast schlauer ;)

        zum parsen des codes kannst du require() anstatt file_get_contents() verwenden, alternativ bietet sich auch eval() an (hier solltest du aber insbesondere die warnhinweise lesen)

        1. Hi,

          zum parsen des codes kannst du require() anstatt file_get_contents() verwenden

          das hat soweit funktioniert.

          Vielen Dank für eure Hilfe.

          Johann

        2. echo $begrüßung;

          die frage ist, ob du nun mit dem php-code das html holst oder mit einem script den php-code und das html-zeug holst und dort beides zusammenfügst

          Deinen Gedankengang, der zu diesem Satz führte konnte ich daraus leider nicht entnehmen.

          prinzipiell ist php ansich als "templateengine" gedacht gewesen, weshalb erster variante näher liegt - nachdem sich php aber zunehmend zur objektorientierten programmiersprache hinentwickelt, ist zweitere lösung schon wieder fast schlauer ;)

          Wenn man Templates in PHP machen möchte, sollte man sich mal die alternative Kontrolstruktur-Syntax ansehen. Damit lassen sich recht ordentlich aussehende Templates schreiben.

          Ob objektorientiert oder nicht ist nicht von Bedeutung. Man kann auch innerhalb einer Methode das PHP verlassen ?>, HTML-Zeug einfügen <?php echo $this->variablen ?> hinzufügen, usw. usf. Alles kein Problem, Objektorientierung und der PHP-als-Template-Ansatz in einem. Als eine gut gelungene Integration von OOP und PHP-Template finde ich die Lösung bei der Zend-Framework-Komponente Zend_View. (Bitte Arbeitsweise im Manual erkunden und dann in den Quellen schauen, wie es realisiert ist.)

          echo "$verabschiedung $name";

          1. Deinen Gedankengang, der zu diesem Satz führte konnte ich daraus leider nicht entnehmen.

            damit war gemeint:
            script (template engine) --------------> output
                ^             ^
                |             |
            template.html  formularcode.php

            im gegensatz zu diesem ansatz
            formularcode.php ----------------------> output
                ^
                |
            template.html

            in ersterem beispiel ist die template-engine ein eigenes script welches das html-template und den zu parsenden php code holt (das php evaluiert) und dann beides zusammenfügt

            der zweite ansatz verzichtet auf die templateengine - der verantwortliche programmcode bindet sein template selbst ein (siehe beispiel unten)

            die dritte, von dir angesprochene möglichkeit, einfach ?> jetzt kommt html <?php war die geschichte mit "php ist ansich schon eine template engine" (das muss man natürlich sehr dehnbar sehen, da man bei "echten templates" markierungen setzt und keinen vollständigen programmcode

            das war mit "php als template-engine" gemeint:
            alternativ lässt sich natürlich das html auch aus einer datei laden und man kann entsprechende elemente durch keys im array ersetzen - zb <!-- §content§ --> wird gegen $templatezeug['content']; ersetzt (vorher prüft noch eine routine, ob der key im array überhaupt vorhanden ist)

            <?php  
            $templatezeug['menu'] = '<ul id="menu" />';  
            $templatezeug['content'] = '<div id="content" />';  
            ?>  
            <body>  
              <p>foo</p>  
              <?=$templatezeug['content'];?>  
              <p>bar</p>  
              <?=$templatezeug['menu'];?>  
            </body>
            
            1. echo $begrüßung;

              die dritte, von dir angesprochene möglichkeit, einfach ?> jetzt kommt html <?php war die geschichte mit "php ist ansich schon eine template engine" (das muss man natürlich sehr dehnbar sehen, da man bei "echten templates" markierungen setzt und keinen vollständigen programmcode

              Man liest oft die Meinung, man müsse Programmcode und HTML-Code voneinander trennen, weswegen man Templates mit Platzhaltern erfand, die man mehr oder wenig aufwendig parst und die notwendigen Ersetzungen vornimmt. Diese Meinung findet sich auch in irgendeinem weit zurückliegenden Archivposting von mir (damals war HTML_Template_IT bzw. _Sigma aus PEAR mein Favorit). Mittlerweile sehe ich die Sache anders. Für mich gehört die Trennung nach Logik sortiert: verarbeitende Logik, Ausgabelogik. Wenn zum Ausgeben der Daten Programmcode benötigt wird, beispielsweise ein Schleifenkonstrukt, dann ist das Ausgabelogik und die hat durchaus ihren berechtigten Platz im Ausgabe-Teil, also im von Ausgabelogik-PHP-Code durchsetzten HTML-Teil.

              Das gesamte Script ist also so aufgeteilt, dass der erste Teil die Daten beschafft und verarbeitet und reine Datenstrukturen unabhängig von konkreten Ausgabebedingungen bereitstellt. Der zweite Teil ist ein HTML-Template mit PHP-Code, der an den vorgesehenen Stellen notiert ist und die Daten ausgibt und sie dabei ausgabegerecht bearbeitet. Dafür können neben einfachen Kontrollstrukturen und Hilfsfunktionen durchaus auch komplexe Helfer eingesetzt werden (die idealerweise aus einer eingebundenen Bibliothek stammen), beispielsweise Datagrids, Navigationselemente oder Formulare erzeugende Funktionen.

              echo "$verabschiedung $name";

              1. Da wär ich nochmal, hoffe das liest noch jemand.

                Hab doch noch Probleme mit der Umsetzung. Wenn ich file_get_contents mit require ersetze, kommt zwar anstatt des Quellcodes mein Formular, aber an der falschen Stelle.

                Mein Template Platzhalter sind so aufgebaut:

                [%top%]
                [%navi%]
                [%subnavi%]
                [%content%]
                [%bottom%]

                In der index.php werden alle Platzhalter nacheinander ersetzt und am Ende die gesamte Seite ausgegeben.
                Setze ich require (in meiner getContent-Funktion)wird zuerst der content anstatt top... angedruckt.

                Einzige Möglichkeit die mir einfällt ist, sobald die Platzhalter gesetzt sind, diese auszugeben um die richtige Reihenfolge beizubehalten.

                Gibt es da vielleicht eine andere/geeignetere Möglichkeit?

                Johann

                1. echo $begrüßung;

                  Gibt es da vielleicht eine andere/geeignetere Möglichkeit?

                  Beschreibe bitte zunächst einmal dein Problem so, dass es ein Außenstehender verstehen und nachvollziehen kann. Am besten wäre ein auf das Minimum verkürztes Beispiel der beteiligten Dateien.

                  echo "$verabschiedung $name";

                  1. Beschreibe bitte zunächst einmal dein Problem so, dass es ein Außenstehender verstehen und nachvollziehen kann. Am besten wäre ein auf das Minimum verkürztes Beispiel der beteiligten Dateien.

                    index.php-Datei:
                            include 'mainTemplate'
                            //Top einslesen und einsetzen
                     $docTop = file_get_contents('Content/top_text.txt');
                     $page = preg_replace("~[%top%]~",$docTop, $page);
                            //navi, subnavi einlesen und einsetzen wie oben bei Top

                    $content = getContent();
                            $page = preg_replace("~[%content%]~", $arr['content'], $page);

                    //bottom einlesen und einsetzen wie oben z.B. bei navi

                    echo $page;

                    function getContent() {
                           $docContent = file_get_contents('check.php');
                           return $docContent;
                    }

                    check.php-Datei:
                           $formular_temp = file_get_contents('formular.txt');
                           if (empty($_POST)) {//keine Daten gesendet --> lade leeres Formular
                      echo "$formular_temp";
                     }else {//Daten gesendet --> pruefe auf korrekte Pflichtfelder
                                   if(ok)
                                    //verarbeite Daten
                                   else
                                    //Fehler rot färben und korrekte Daten einfürgen echo "$formular_temp";
                            }

                    formular.txt-Datei:
                          <form action="Statisch/Content/Texte/add.php" method="post" enctype="multipart/form-data">
                          <input ....>
                          </form>

                    Mein Ausgangsproblem war, dass in der index.php der Quelltext von check.php anstatt dem Formular ausgegeben wurde.
                    Der Hinweis von suit anstelle von file_get_contents besser require zu nehmen hat zwar funktioniert, doch die Ausgabe des Formulars (dem content) war dann vor [%top%], [%navi%] und [%subnavi%]. Vermutlich wird mit require(Inhalt) der Inhalt sofort angedruckt.
                    Falls dem so ist hätte ich gern gewusst, ob es eine gängigere Möglichkeit gibt, als in der index.php alle Platzhalter nach dem Ersetzen gleich auszugeben.

                    Johann

                    1. echo $begrüßung;

                      Beschreibe bitte zunächst einmal dein Problem so, dass es ein Außenstehender verstehen und nachvollziehen kann. Am besten wäre ein auf das Minimum verkürztes Beispiel der beteiligten Dateien.

                      Es ist immer noch nicht vollständig nachvollziehbar. Es fehlt das zu deiner Frage passende Problem. Es sind keine [%foo%]s in deinen Texten zu sehen, die ersetzt werden sollen. So weiß ich immer noch nicht ganz genau, wann sie nun in welcher Form vorliegen.

                      $page = preg_replace("~[%top%]~",$docTop, $page);

                      [%foo%] ist kein Muster sondern nur ein einfacher String. Somit brauchst du auch keine aufwändige Mustererkennungsfunktion zu verwenden, sondern kannst mit einfachen Stringersetzungsfunktionen (str_replace() oder strtr()) arbeiten.

                      echo "$formular_temp";

                      Anführungszeichen um Variablennamen ohne weiteren Text sind überflüssig.

                      $formular_temp = file_get_contents('formular.txt');
                             if (empty($_POST)) {//keine Daten gesendet --> lade leeres Formular

                      Dein eigentliches Problem ist, dass du Eingabe, Verarbeitung und Ausgabe nicht trennst sondern munter miteinander mischst. So kommst du in die Bredouille, dass du noch Eingabewerte verarbeiten musst, aber da schon auf Zeichenfolgen der Ausgabe Acht geben musst. Zum Auswerten von Formulardaten braucht man allein das $_POST-Array. Der HTML-Text vom Formular ist dabei nicht notwendig. Sammle alle beim Auswerten der Eingabedaten aufgetretenen Fehlermeldungen in einer geeigneten Struktur. Ermittle alle weiteren Daten, die für die Ausgabe benötigt werden, und erst wenn du alles zusammenhast, erzeuge die Ausgabe und arbeite dabei die Daten ein. Das kann durchaus auch mit Suchen und Ersetzen in einem aus einer Datei geladenen Templates geschehen.

                      Mein Ausgangsproblem war, dass in der index.php der Quelltext von check.php anstatt dem Formular ausgegeben wurde.

                      Für mich stellt es sich nun so dar, dass in der check.php PHP-Verarbeitung stattfindet und das Ergebnis ein Text ist, der zu ersetzende Platzhalter enthält. Man kann das auf zwei Arten lösen, sofern du keine grundlegende Strategieänderung aufgrund meiner obigen Ausführung willst. Zum einen kann man die Ausgabe puffern, zum anderen kann man von vorn herein seinen auszugebenden Text in einer Variable sammeln. In beiden Fällen kann man nun noch Stringverarbeitung vornehmen, bevor man alles ausgibt.

                      echo "$verabschiedung $name";

                      1. Erst nochmal ein Danke für eure investierte Zeit und die guten Tipps.

                        Für mich stellt es sich nun so dar, dass in der check.php PHP-Verarbeitung stattfindet und das Ergebnis ein Text ist, der zu ersetzende Platzhalter enthält.

                        Eigentlich soll die check.php folgendes machen (Affenformular):
                        -ein leeres Formular laden
                        -auf korrekte eingaben prüfen
                          bei korrekter Eingabe die Daten in DB schreiben und eine andere Seite laden
                          bei fehlerhafter Eingabe das Formular laden, die Fehler rot markieren und die eingegebene Daten im Formular anzeigen
                        Der submit-button des Formulars (formular.txt) ruft die check.php auf.

                        Mir ist nicht ganz klar wo das Problem bei der check.php und dem Vermischen von Eingabe, Verarbeitung und Ausgabe liegt.
                        Die check.php steuert über if-Anweisungen die Ausgabe je nachdem ob:
                        eine korrekte Eingabe vorliegt die in eine DB geschrieben wird oder ob im Formular die css-Eigenschaft (z.B. border:red;) bei Fehleingabe gesetzt wird oder falls noch keine Benutzereingaben vorliegen das leere Formular anzeigt.

                        Stattdessen könntest Du auch einfach im HTML <?php readfile('Content/top_text.txt'); ?> notieren. Und Dein Problem lässt sich damit auch ohne sinnvolle Umstrukturierung lösen

                        Guter Hinweis, doch ich würde eine sinnvolle Umstrukturierung bevorzugen.  Ich möchte nicht nur dieses Problem "schnell" lösen, sondern lernen welche sinnvolle Strukturmöglichkeit es gibt, die auf möglichst viele Projekte anwendbar ist. Vermutlich ist es vom jeweiligen Vorhaben abhängig, doch vielleicht gibt es ja eine Art "best-practise" oder eine geeignete Grundstruktur die ich mir verinnerlichen kann. Hab bisher leider kein passendes deutschsprachiges Tutorial finden können das mir weitergeholfen hat.

                        Viele Grüße
                        Johann

                        1. echo $begrüßung;

                          Eigentlich soll die check.php folgendes machen (Affenformular):
                          -ein leeres Formular laden
                          -auf korrekte eingaben prüfen
                            bei korrekter Eingabe die Daten in DB schreiben und eine andere Seite laden
                            bei fehlerhafter Eingabe das Formular laden, die Fehler rot markieren und die eingegebene Daten im Formular anzeigen
                          Der submit-button des Formulars (formular.txt) ruft die check.php auf.

                          Mir ist nicht ganz klar wo das Problem bei der check.php und dem Vermischen von Eingabe, Verarbeitung und Ausgabe liegt.

                          Der verarbeitende Teil trägt alle Informationen zusammen, die für eine Ausgabe benötigt werden, gibt sie aber nicht aus. Das betrifft auch Fehlermeldungen, die an den Anwender ausgegeben werden sollen. (Meldungen, die interne Logfiles geschrieben werden sollen, können gleich dorthin ausgegeben werden.) Erst wenn alle Daten ermittelt wurden, kommt die Ausgabe zum Zuge. Dieser Programmteil greift nun auf die bereitgestellten Variablen mit den einzufügenden Texten zu und arbeitet sie an den passenden Stellen im Template ein.

                          Zur Formularauswertung benötigt man nur das $_POST-Array. Der HTML-Code vom Formular ist dabei unwichtig. Er muss deshalb an der Stelle nicht geladen sein.

                          Solch eine Trennung ist vorteilhaft, weil man sich damit die möglichen Wege durch eine bereits erfolgte teilweise Ausgabe nicht verbaut. Wenn das Formular erfolgreich abgearbeitet wurde, ist es vielleicht erforderlich, auf eine andere Seite weiterzuleiten, damit der Zurückblättern-und-"POST-Daten-noch-mal-senden?"-Effekt nicht auftritt. Eine vorherige Ausgabe stört dabei und das Formular wurde in dem Fall auch umsonst geladen. Will man diese Weiterleitung später noch einbauen ist das nicht ohne größere Umbauarbeiten möglich oder zumindest schwierig. Alternativ könnte man die Ausgabe puffern, was dann aber auch umsonst war, wenn man ohne Ausgabe weiterleitet.

                          Guter Hinweis, doch ich würde eine sinnvolle Umstrukturierung bevorzugen. Ich möchte nicht nur dieses Problem "schnell" lösen, sondern lernen welche sinnvolle Strukturmöglichkeit es gibt, die auf möglichst viele Projekte anwendbar ist.

                          Das, denke ich, ist eine gute Entscheidung.

                          Vermutlich ist es vom jeweiligen Vorhaben abhängig, doch vielleicht gibt es ja eine Art "best-practise" oder eine geeignete Grundstruktur die ich mir verinnerlichen kann. Hab bisher leider kein passendes deutschsprachiges Tutorial finden können das mir weitergeholfen hat.

                          Vielleicht hilft dir schon meine Vorgehensweise bei auszugebenden Fehlermeldungen weiter. Ein Formularelement hat ja einen Namen. Wenn bei der Eingabedatenprüfung ein Fehler festgestellt wurde, erstelle ich in einem Array $errors ein Element mit dem Formularelementnamen als Schlüssel. Dieses Element ist wiederum ein Array, das die einzelnen Fehlermeldungstexte enthält.

                          $errors = array(
                              'element1' => array(
                                'meldung 1',
                                'meldung 2'),
                              'element2' => array(
                                'meldung 1'));

                          Im Ausgabeteil kann man nun entscheiden, ob man alle Meldungen an einer Stelle ausgeben will oder ob man sie in der Nähe des jeweils betroffenen Elements platziert. Im ersten Fall kann man über das Array und seine Unterarrays iterieren, im zweiten Fall prüft man bei der Ausgabe des jeweiligen Elements, ob im Fehlerarray etwas Passendes enthalten ist. Dazu kann man sich eine Helferfunktion schreiben, die über das Unterarray iteriert, damit dieser Code nicht mehrfach eingefügt werden muss. Und wenn $errors ganz leer war, kann man das Formular komplett ignorieren und die Weiterleitung ausführen.

                          echo "$verabschiedung $name";

                          1. Hi,

                            vermutlich hab ich mich schlecht bzw. falsch ausgedrückt.

                            Zur Formularauswertung benötigt man nur das $_POST-Array. Der HTML-Code vom Formular ist dabei unwichtig. Er muss deshalb an der Stelle nicht geladen sein.

                            Bei der Auswertung benutze ich nur das $_POST-Array in Form von if-Bedingungen. Je nachdem welche if-Bedingung zutrifft, wird das Formular im entsprechenden if-Block verändert und anschließend (im gleichen if-Block) ausgegeben. Damit das Formular nicht in jedem möglichen if-Block geladen werden muss mach ich das am Anfang des Scripts.
                            Die Ausgabe erfolgt erst nachdem die Auswertung abgeschlossen ist und das Formular entsprechend des if-Blocks manipuliert ist.

                            Da ich auf keine eigenen Erfahrungen zurückgreifen kann habe ich ein Script aus dem Netz "nachgebaut" das mir passend erschien.
                            Hast du mich schon vorher richtig verstanden, dann Entschuldige meine erneute Ausführung. Ansonsten interessiert mich natürlich, ob dieser Scriptaufbau andere Schwächen hat oder gut verwendbar ist.

                            Bin noch nicht richtig dazugekommen, doch werden ich deine Vorgehensweise näher betrachten und schaun ob ich sie bei mir verwenden kann.

                            Johann

                            1. echo $begrüßung;

                              Zur Formularauswertung benötigt man nur das $_POST-Array. Der HTML-Code vom Formular ist dabei unwichtig. Er muss deshalb an der Stelle nicht geladen sein.
                              Bei der Auswertung benutze ich nur das $_POST-Array in Form von if-Bedingungen. Je nachdem welche if-Bedingung zutrifft, wird das Formular im entsprechenden if-Block verändert und anschließend (im gleichen if-Block) ausgegeben. Damit das Formular nicht in jedem möglichen if-Block geladen werden muss mach ich das am Anfang des Scripts.

                              Das Formular soll zu diesem Zeitpunkt noch gar nicht geändert werden. Das meine ich mit Trennung nach EVA. Es sollen in dem Schritt nur Daten gesammelt werden, und das ohne auf Spezifika der späteren Ausgabe näher einzugehen. Also keinerlei Formatierung oder Ausgabemedium-spezifische Besonderheiten einarbeiten.

                              Die Ausgabe erfolgt erst nachdem die Auswertung abgeschlossen ist und das Formular entsprechend des if-Blocks manipuliert ist.

                              Zur Ausgabe gehört nicht nur das eigentliche Übergeben an das Ausgabemedium sondern auch das Aufbereiten dafür. In deinem Fall also das Manipulieren des Formulars und der Texte, die eingefügt werden sollen.

                              echo "$verabschiedung $name";

                2. Hello,

                  Gibt es da vielleicht eine andere/geeignetere Möglichkeit?

                  Da ich noch immer nicht weiß, was eigentlich genau klemmt, verweise ich Dich mal auf einen alten Thread, der sich damit schon mal auseinandergesetzt hat und ein paar Beispiele enthält.

                  http://forum.de.selfhtml.org/archiv/2008/8/t175925/#m1159112

                  Liebe Grüße aus Syburg bei Dortmund

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                3. Hi,

                  Mein Template Platzhalter sind so aufgebaut:

                  [%top%]
                  [%navi%]
                  [%subnavi%]
                  [%content%]
                  [%bottom%]

                  ich würde mir an Deiner Stelle überlegen, ob es hier wirklich angebracht ist, mit Platzhaltern zu arbeiten. Stattdessen könntest Du auch einfach im HTML <?php readfile('Content/top_text.txt'); ?> notieren. Und Dein Problem lässt sich damit auch ohne sinnvolle Umstrukturierung lösen, indem Du an der gewünschten Stelle im HTML einfach die <?php if($Formular_soll_angezeigt_werden) require('check.php') ?> notierst.

                  freundliche Grüße
                  Ingo

                  1. ich würde mir an Deiner Stelle überlegen, ob es hier wirklich angebracht ist, mit Platzhaltern zu arbeiten.

                    das macht das template aber sprachunabängig - mir fällz zwar spontan nichts ein, aber es gibt sicher template-engines in mehreren sprachen ;)

  2. Hello,

    wenn Du erst herausfinden willst, was das Include-File anstellen wird, kannst Du auch mit dem Output-Buffer arbeiten

    ob_start();
        include <file>;
        $result = ob_get_clean();

    http://www.php.net/manual/en/function.ob-get-clean.php

    Dann stehen die Ausgaben, die das Include verusacht hat, nachher in $result.
    Das Include kann aber trotzdem noch Auswirkungen auf andere Stellen des Scriptes haben, z.B. durch Veränderung von Variablen oder Benutztung von Dateien...

    Liebe Grüße aus Syburg bei Dortmund

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de