Norbert: In Template-generierter Seite inkludierten Code ausführen

Hallo!

Für eine Seite brauche ich ein simples Templatesystem, das vereinfacht so aussieht:

index.php

<?php

$seite = file_get_contents("/tpl/index.tpl");

include "/tpl/tpl.php";

?>

Die Templatedatei tpl.php sieht dann vereinfacht so aus:

<html>

usw.

<body>

<?echo $seite ?>

<body>
</html>

Problematisch wird es, wenn die Inhaltsdatei index.tpl selbts ausführbaren Code enthalten soll, etwa um ein Formular zu erzeugen u.ä.:

/tpl/index.tpl

<p>Das ist der Inhalt von index.php</p>

<p>Ich liege unter <?php echo $_SERVER['PHP_SELF'] ?></p>

Da file_get_contents() eine Zeichenkette erwartet, wird der Code nicht ausgeführt. Gibt es eine einfache Lösung für das Problem, ohne eine richtige Template-Maschine einsetzen zu müssen?

  1. Lieber Norbert,

    Gibt es eine einfache Lösung für das Problem, ohne eine richtige Template-Maschine einsetzen zu müssen?

    Du kannst Dir Deine eigene "richtige" Template-Maschine bauen, die extrem simpel aufgebaut ist.

    Schreibe Dein Formular doch so:

    <body>....  
    <!-- tpl:formular -->  
    ...</body>
    

    Du kannst dann anstatt gleich mit <?php echo $seite ?> (verwende unbedingt die Langform, sonst gibt's Ärger mit "<?xml"!) Deine Seite auszugeben zuerst auf ein Vorhandensein des HTML-Kommentars prüfen, um dann diesen mit echtem HTML-Code zu ersetzen.

    Sollte eine Seite kein Formular benötigen, kannst Du entweder den HTML-Kommentar belassen (er bewirkt im Browser ja nichts), oder Du kannst ihn vor der Ausgabe entfernen, da Dein Script ihn in jedem Falle ersetzt, falls nicht benötigt eben mit einem Leerstring... Das könnte dann so aussehen:

    <?php  
      
    $seite = file_get_contents('/tpl/index.tpl');  
      
    include '/tpl/tpl.php'; // was passiert hier eigentlich???  
      
    $formular = ''; // leer für "nicht benötigt"  
    // jetzt kannst Du im Bedarfsfalle Dein Formular erstellen und den HTML-Code in $formular ablegen.  
      
    // Formular-Kommentar löschen bzw. mit echtem HTML-Code ersetzen:  
    $seite = str_replace ('<!-- tpl:formular -->', $formular, $seite);  
      
    echo $seite; // kompletten HTML-Code an Browser schicken  
      
    // Script-Ende  
    ?>
    

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo Felix!

      Du hast die Logik der Ausgabe mißverstanden.

      Schreibe Dein Formular doch so:

      <body>....

      <!-- tpl:formular -->
      ...</body>

      
      >   
        
      Die eigentliche Ausgabe findet durch die /tpl/tpl.php statt, nicht in der index.php. Die liefert nur den Inhalt an die /tpl/tpl.php.  
        
        
      
      > Sollte eine Seite kein Formular benötigen, kannst Du entweder den HTML-Kommentar belassen (er bewirkt im Browser ja nichts), oder Du kannst ihn vor der Ausgabe entfernen, da Dein Script ihn in jedem Falle ersetzt, falls nicht benötigt eben mit einem Leerstring... Das könnte dann so aussehen:  
      >   
      > ~~~php
      
      <?php  
      
      >   
      > $seite = file_get_contents('/tpl/index.tpl');  
      >   
      > include '/tpl/tpl.php'; // was passiert hier eigentlich???  
      >   
      > $formular = ''; // leer für "nicht benötigt"  
      > // jetzt kannst Du im Bedarfsfalle Dein Formular erstellen und den HTML-Code in $formular ablegen.  
      >   
      > // Formular-Kommentar löschen bzw. mit echtem HTML-Code ersetzen:  
      > $seite = str_replace ('<!-- tpl:formular -->', $formular, $seite);  
      >   
      > echo $seite; // kompletten HTML-Code an Browser schicken  
      >   
      > // Script-Ende  
      > ?>
      
      

      $seite = file_get_contents('/tpl/index.tpl'); steht in der index.php.
      Das echo $seite steht in der /tpl/tpl.php.

      Das sind also zwei unterschiedliche Dateien. Die /tpl/index.tpl hat nur den Zweck, Logik und Layout möglichst zu trennen. Die eigentliche Schablone ist die /tpl/tpl.php. Dazwischen steht als Bindeglied die index.php, in der seitenspezifischer Code ausgeführt wird.

      1. Lieber Norbert,

        Die eigentliche Ausgabe findet durch die /tpl/tpl.php statt, nicht in der index.php. Die liefert nur den Inhalt an die /tpl/tpl.php.

        muss ich das jetzt für besonders sinnvoll erachten?

        Meiner Meinung nach sollte das Haupscript (in Deinem Falle index.php) alle anderen Scripte organisieren, um am Ende die eigentliche Ausgabe an den Browser zu schicken. Alle anderen eingebundenen Scripte sollten nur am noch nicht ausgegebenen Code herummodifizieren, jedoch keinesfalls diesen bereits an den Browser schicken, da sonst wesentliche Dinge wie z.B. Cookies oder andere HTTP-Header nicht mehr gesendet werden können, falls man im Programmverlauf feststellen sollte, dass man diese benötigt.

        Mein Vorschlag: Ändere Deine Programmlogik dahingehend, dass Du (von mir aus in einer globalen Variablen) den bisher erzeugten HTML-Code bereithälst, bevor ihn Deine index.php endgültig an den Browser schickt. Deine tpl.php darf an diesem Code nur "herumfummeln", ihn jedoch keinesfalls per echo irgendwohin schicken!

        Damit hast Du dann Deine ursprüngliche Frage beantwortet, die nach einer "richtigen" Template-Maschine gestellt war. Wenn Du nämlich den HTML-Code bis zum Ende des Scripts in einer Variablen vorhälst, dann kannst Du mit verschiedenen Unter-Scripts die verschiedensten Teilbereiche Deines Templates abarbeiten, bis dann am Ende je nach Anforderung ein passendes HTML-Dokument fertiggestellt ist.

        Beispiel (nicht besonders gut, klärt aber meine Sichtweise):

        <?php // index.php  
          
        include '/tpl/unterseiten.php'; // enthält ein Array mit möglichen IDs und deren Templates  
          
        $seite = 'index'; // default  
          
        if (isset($_GET['id']) && $_GET['id'] != '') {  
            // andere Unterseite aufrufen?  
            $seite = $_GET['id'];  
        }  
          
        $seite = $seite.'.tpl'; // Vorsicht! Ungeprüfte IDs könnten ein Sicherheitsrisiko werden!  
          
        include '/scripts/tpl.php'; // holt die benötigte Template-Datei mit einem vorläufigen HTML-Code und speichert ihn in $GLOBALS['html']  
          
        include '/scripts/formular.php'; // Formular einbauen? (ändert den bisherigen Code in $GLOBALS['html'] falls notwendig)  
          
        include '/scripts/gb.php'; // soll gb angezeigt werden?  
        ...  
          
        echo $GLOBALS['html']; // HTML-Dokument an Browser ausgeben und Ende  
        ?>
        

        Liebe Grüße aus Ellwangen,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Hallo Felix!

          Wir reden leider immer noch aneinander vorbei! Du versteifst Dich auf den Gedanken, die index.php solle die Template-Datei sein. Alle anderen Seiten würden dann per Query-String immer über diese index.php ausgegeben.

          Genau so soll es aber nicht sein. Jede Seite soll durch eine eigene Datei repräsentiert werden, d. h., um unterschiedliche Seiten anzuzeigen, sollen auch unterschiedliche URLs in die Browserleiste eingegeben werden, der Grund hierzu spielt an dieser Stelle keine Rolle. Die Folge ist also, daß die Templatedatei von den jeweiligen Seiten eingebunden werden soll und selbst niemals direkt aufgerufen wird. Die Template-Datei muß an den Stellen, wo sie variable Inhalte ausgeben soll, fertigen HTML-Code geliefert bekommen, der von den jweiligen Seiten generiert wird. Daraus resultiert die Anforderung, daß aus den eigentlichen Inhaltsseiten ausgelagerte Inhalte selbst wiederum an die Inhaltsseiten HTML-Code liefern müssen, weil sie nicht inkludiert, sondern nur mit file_get_contents() eingebunden werden können.

          Ist das Problem jetzt klarer?

          1. Hallo.

            Du versteifst Dich auf den Gedanken, die index.php solle die Template-Datei sein.

            Das ist nicht nur gängig, sondern vor allem logisch, denn Index-Ressourcen fassen ja die übrigen Ressourcen sinnvoll zusammen, wenn sie ihrer Bezeichnung gerecht werden wollen.

            Alle anderen Seiten würden dann per Query-String immer über diese index.php ausgegeben.

            Zum Beispiel. Man könnte natürlich auch mit Verzeichnissen und jeweils einer eigenen index.php im jeweiligen Verzeichnis arbeiten. Oder mit Content Negotiation, wenn es beispielsweise um unterschiedliche Sprachversionen ginge. Dann entfiele der Query-String.

            Jede Seite soll durch eine eigene Datei repräsentiert werden, d. h., um unterschiedliche Seiten anzuzeigen, sollen auch unterschiedliche URLs in die Browserleiste eingegeben werden, der Grund hierzu spielt an dieser Stelle keine Rolle.

            Aber vielleicht der Grund dafür, dass du meinst, man müsse dem URI überhaupt ansehen, wie du deine Ressourcen benennst. Verwende doch mod_rewrite. Das ist ja schon wegen der unpraktischen Endung .php anzuraten.

            Ist das Problem jetzt klarer?

            Es ist zumindest klarer, dass du dir eines schaffst, wo vielleicht keines sein müsste.
            MfG, at