Torsten: CMS Smarty

Hallo Forum,

in einem meiner Projekte habe ich mit PHP und MySQL gearbeitet. Dieses Projekt möchte ich jetzt in ein CMS umbauen. Eines der Gründe ist, den Code sauber vom Design zu trennen. Ich habe mich für Smarty entschieden aus einen einfachen Grund, ich fand Smarty im Buch "Besser PHP Programmieren" von Carsten Mörke. Dort wurde unter anderem beschrieben das es eine ganz tolle und professionelle Sache sei Programmlogik vom Design sauber zu trennen. Dies wollte ich natürlich dann auch sofort ausprobieren. Nur desto mehr ich mit Smarty arbeite, desto mehr überlege ich mir ob es überhaupt einen Sinn macht damit weiter zu machen. Es entstehen dabei diverse Probleme die mir das Entwickeln schwerer, umständlicher und zeitaufwendiger machen, wie z.B. die Navigation. Wenn ich's mir so recht überlege, eigentlich will ich ja nur den PHP-Code vom HTML-Code sauber trennen, dann könnte ich das ja auch mit externen Bibliotheken machen. In gewisser Weiße ist dieses Projekt auch schon eine Art CMS, User können Daten der Website ändern. Das einzige was eben nicht ist, die Programmlogik ist nicht sauber vom Design getrennt. Was haltet Ihr von CMS und Smarty?

Wie oben schon erwähnt, habe ich Probleme mit der realisierung der Navigation in Smarty.

Navigation mit PHP ohne Smarty (index.php):
<head>
<?php
  if ($page == "") $page = "start.htm";
?>
</head>
<body>
<div class="nav">
  <a href="index.php?page=seite1.htm">Home</a><br>
  ...
</div>
<div class="content><?php include($page); ?></div>
</body>

hier wäre die Programmlogik nicht vom Design getrennt.
Wie soll ich das jetzt mit Smarty machen? Was ich beim googeln gefunden habe ist so was wie {include file="start.tpl"}.
Die IF-Anweisung im Head müsste ja dann auch in die PHP-Datei, ich probiere das jetzt schon seid Stunden, ich bekomme es einfach nicht hin. Und das ist nur ein kleines Problem, ich will nicht wissen was für Schwierigkeiten ich später noch bekommen werde. Deswegen meine Frage, ob es überhaupt empfehlenswert ist Smarty zu verwenden.

Wie man diese Navigation in Smarty macht würde ich mich über etwas Beispiel-Code sehr freuen.

Gruß
Torsten

  1. Hallo,

    Ohne auf das eigentlich Thema Deines Threads einzugehen, ein Hinweis zu folgendem Code, der ein Sicherheitproblem darstellen kann.

    <div class="nav">
      <a href="index.php?page=seite1.htm">Home</a><br>
      ...
    </div>
    <div class="content><?php include($page); ?></div>

    Folgendes kann möglich sein: http://deine-seite.de/index.php?page=http://boese.de

    Mit freundlichen Grüßen,
    Andreas Waidelich

    --
    signatures eat bandwidth
    1. Hallo Andreas,

      Ohne auf das eigentlich Thema Deines Threads einzugehen, ein Hinweis zu folgendem Code, der ein Sicherheitproblem darstellen kann.

      Folgendes kann möglich sein: http://deine-seite.de/index.php?page=http://boese.de

      genau, ist mir auch schon aufgefallen.
      Wie könnte man es besser machen?
      Kann man den Query-String vielleicht irgendwie verstecken?

      Gruß
      Torsten

      1. echo $begrueszung;

        Folgendes kann möglich sein: http://deine-seite.de/index.php?page=http://boese.de
        Wie könnte man es besser machen?

        page erhält nur einen ganz bestimmten Wertevorrat, auf den und nur auf den du in deiner Datei prüfst. Man kann dies mit switch tun oder mit einem Array

          
          $pageNr = isset($_GET['page']) ? $_GET['page'] : 0;  
          $pages = array(  
            1 => 'seite1.html',  
            2 => 'seite2.html');  
          $page = array_key_exists($pageNr, $pages) ? $pages[$pageNr] : 'default.html';  
        
        

        In diesem Beispiel wären die erlaubten Werte 1 und 2. Diese führen auf die entsprechende Seite. Alles andere führt zu default.html.

        echo "$verabschiedung $name";

  2. Hi,

    wenn man sich selbst ein paar Gedanken macht und gewisse Regeln einhält, ist Smarty meiner Meinung nach überflüssig.

    Hier ein Beispiel, wie ich mit Standard-PHP die Logik vom Design trennen kann. Man sollte sich im Design nur auf include und print Anweisungen beschränken...

    index.php:

    <?php include "logik.php"; ?>
    <head>
    </head>
    <body>
    <div class="nav">
      <a href="index.php?page=seite1.htm">Home</a><br>
      ...
    </div>
    <div class="content><?php include $page; ?></div>
    </body>

    logik.php:

    <?php
      if ($page == "" or $page == "start") {
        $page = "start.htm";
      }
    ?>

    freundlichen Gruß
    Danny

    --
    Selfcode: fo:) br:& n4:& ie:% mo:) va:| de:] zu:) fl:| ss:) ls:& ls:& js:|
    Motto:    OpenSource - Das Wissen der Menschheit gehört der Welt!
    1. echo $begrueszung;

      wenn man sich selbst ein paar Gedanken macht und gewisse Regeln einhält, ist Smarty meiner Meinung nach überflüssig.

      Dem stimme ich zu, allerdings nur, solange es sich dabei um kleinere Pojekte handelt, die man als Webdesigner und Programmierer in Personalunion ausführt.
      Wenn es darum geht, diese Aufgaben in getrennte, spezialisierte Hände zu vergeben spielt die  Templates-Technik ihre Vorteile aus.

      Und, ob man (beispielsweise) die foreach-Logik zur Ausgabe der Daten zum einen oder zum anderen Teil zählt ist mehr oder weniger eine Philosophie-Frage.

      echo "$verabschiedung $name";

  3. Hi Torsten,

    ich bin begeistert von Smarty...Also ist schwon mal klar auf welcher Seite ist stehe :-)
    Ich muss zugeben, in deinem Fall würde smarty wirklich mehr aufwand bereiten. Aber die hättest Code und design getrennt....

    In Smarty könnte das ganze so gehen:
    logik.php:

    <?php

    if ($_GET['page']=="") {
        $page="start.htm;
    }
    //liest die Datei in eine Varible.
    $handle = fopen ($page, "r");
    $contents = fread ($handle, filesize ($page));
    fclose ($handle);

    //Und dann musst du das in das Template einbinden
    $smart->assign("inhalt",$contents);

    ------------------------------------
    In deinem Template müsstest du dann an der Stelle
    wo du den Include machst, "inhalt" als Variable angeben.

    Mehr sinn macht Smarty wenn du Beispielsweise mit Datenbanken arbeitest. Dann kannst du die Felder auslesen und mit Smarty einbinden, Tabellen ausgeben....

    Also, schau die nochmal Smarty an....ist wirklich cool!

    Navigation mit PHP ohne Smarty (index.php):
    <head>
    <?php
      if ($page == "") $page = "start.htm";
    ?>
    </head>
    <body>
    <div class="nav">
      <a href="index.php?page=seite1.htm">Home</a><br>
      ...
    </div>
    <div class="content><?php include($page); ?></div>
    </body>

    Tschau Christof

    1. Hi,

      ich muß zugeben, das Smarty nicht schlecht ist und wirklich alles im Bereich Templates bietet, was man braucht oder irgendwann mal brauchen könnte.
      Aber trotzdem bleibe ich bei der Meinung, daß man in vielen Fällen eigentlich keine "mächtige" Template-Engine wie Smarty braucht, weil PHP selbst bereits genug Möglichkeiten bietet, um Code und Design zu trennen.

      Etwas wie

      $smart->assign("inhalt",$contents);

      läßt sich in Standard-PHP z.B. einfach so umsetzen:

      Datei logik.php:

      $inhalt = $contents;
      include("design.php");

      Datei design.php:

      print <<<__HTML__
      <html>
      <head>
        <!-- ... -->
      </head>
      <body>
      <div class="content>$inhalt</div>
      </body>
      </html>
      __HTML__

    2. Hi Christof,

      //liest die Datei in eine Varible.
      $handle = fopen ($page, "r");
      $contents = fread ($handle, filesize ($page));
      fclose ($handle);

      Irgendwie hab ich ein Problem mit fopen welches ich mir nicht erklären kann.
      Mit
      $handle = fopen("start.htm", "r");
      bekomme ich folgende Fehlermeldung:
      Parse error: parse error, unexpected T_STRING in C:\xampp\htdocs\index.php on line 9

      die Datei start.htm befindet sich im Ordner htdocs/
      line 9 ist $handle = fopen("start.htm", "r");

      Gruß
      Torsten

      1. Hi,

        Irgendwie hab ich ein Problem mit fopen welches ich mir nicht erklären kann.

        Problem lag an:
        if ($_GET['page'] == "") {
        $page = "smarty/templates/start.tpl;
        }

        mit if ($page == "") $page = "smarty/templates/start.tpl"; gehts!?!?

        Gruß
        Torsten

    3. Hi nochmal,

      In Smarty könnte das ganze so gehen:
      logik.php:

      <?php

      if ($_GET['page']=="") {
          $page="start.htm;
      }
      //liest die Datei in eine Varible.
      $handle = fopen ($page, "r");
      $contents = fread ($handle, filesize ($page));
      fclose ($handle);

      das Problem hierbei ist allerdings auch das ich nur tpl-Dateien öffnen kann. Was ist aber wenn ich in meiner Navigation einen Content öffnen will mit Datenbankanbindungen oder sonstiger PHP-Code der in diesem Contene benötigt wird?

      Ich glaube ich werde wohl doch auf Smarty verzichten müssen...
      Ich erkenne immernoch keinen Vorteil an dieser ganzen Sache.

      Gruß
      Torsten

      1. Hi Torsten,

        Ich glaube ich werde wohl doch auf Smarty verzichten müssen...
        Ich erkenne immernoch keinen Vorteil an dieser ganzen Sache.

        Naja, der Vorteil liegt doch daran, dass Du Design und Logik wirklich trennen willst. Wenn zum Beispiel bei einem Re-Design die Logik sich nicht ändert, musst du bei "deiner version" jede PHP Seite nach HTML elementen durchsuchen. Beim Testen des Designs, testest du außerdem immer auch gleich die Logik mit.
        Bei der Smarty hingegen schuast Du Dir nur die tpl Datein an. Das kannst Du sogar zur not auch mit einem WYSIWYG Programm machen.

        Und nochmal:
        Sowohl der PHP Code als auch der HTML Code bleibt einfacher zu überschauen.

        Zu deiner Frage mit den Datenbanken/ bzw Arrays:

        Du liest die Daten aus der DB in ein Array ein.
        Danach übergibst Du das array deinem Template.

        in  deinem tpl verwendest Du dann folgendes:

        {section name=kunde loop=$KundenId}
        id: {$KundenId[kunde]}<br>
        {/section}
        und schon hast Du alle KundenId's untereinander.

        Kannst da natürlich auch ne Tabelle drum herum bauen:
        <table>
        {section name=kunde loop=$KundenId}
            <tr><td>
            id: {$KundenId[kunde]}<br>
            </td></tr>
        {/section}
        </table>

        Smarty bietet außerdem schon direkt die Möglichkeit Arrays als Tabellen ausgeben zu lassen. Schau dich einfach mal intensiv in der Doku um.

        MfG
        Christog

        1. Hi,

          in  deinem tpl verwendest Du dann folgendes:

          {section name=kunde loop=$KundenId}
          id: {$KundenId[kunde]}<br>
          {/section}
          und schon hast Du alle KundenId's untereinander.

          Kannst da natürlich auch ne Tabelle drum herum bauen:
          <table>
          {section name=kunde loop=$KundenId}
              <tr><td>
              id: {$KundenId[kunde]}<br>
              </td></tr>
          {/section}
          </table>

          Aha. Und das nennst Du dann Logik und Design trennen? ...
          Vielleicht ist das zu "strict" gedacht, aber ist loop denn nicht auch Logik? Loops machen den Code doch wieder "dirty", dann hat man keine tatsächliche Trennung und fast schlimmer noch, zusätzliche fremde Syntax im Code...

          MfG
          Danny

          1. Hi,

            Aha. Und das nennst Du dann Logik und Design trennen? ...
            Vielleicht ist das zu "strict" gedacht, aber ist loop denn nicht auch Logik? Loops machen den Code doch wieder "dirty", dann hat man keine tatsächliche Trennung und fast schlimmer noch, zusätzliche fremde Syntax im Code...

            genau das gefällt mir auch nicht!
            Noch ein Grund warum ich als Anfänger mit Smarty mir überlege, macht es überhaupt sin!?

            Gruß
            Torsten

            1. Hi,

              Aha. Und das nennst Du dann Logik und Design trennen? ...
              Vielleicht ist das zu "strict" gedacht, aber ist loop denn nicht auch Logik? Loops machen den Code doch wieder "dirty", dann hat man keine tatsächliche Trennung und fast schlimmer noch, zusätzliche fremde Syntax im Code...

              genau das gefällt mir auch nicht!
              Noch ein Grund warum ich als Anfänger mit Smarty mir überlege, macht es überhaupt sin

              Für mich schon...ich trenne programmlogik von ausgabelogik. und der mehraufwand ist das mir wert :-)

              Christof

              Gruß
              Torsten

        2. Hi,

          ok werde mal eingehender die Doco lesen.
          Vielleicht könntest Du mir noch bei einer kleinen Sache helfen?

          if ($_GET['page']=="")
            $page="start.htm;

          funktioniert nicht, mit globalen Variablen gehts.

          Gruß
          Torsten

      2. echo $begrueszung;

        das Problem hierbei ist allerdings auch das ich nur tpl-Dateien öffnen kann. Was ist aber wenn ich in meiner Navigation einen Content öffnen will mit Datenbankanbindungen oder sonstiger PHP-Code der in diesem Contene benötigt wird?

        Hier stimmt was mit deiner Logik nicht. Von deiner Ausgabetechnik möchtest du Programmlogik nachladen, die dann wieder Ausgabe erzeugen soll...

        Ich schlage vor, deine Teilbereiche zu modularisieren.

        Zum Beispiel gibt das Navigationsmodul einen fertigen HTML-Teil als String zurück, der in deinem Haupt-Template an passender Stelle eingefügt wird.

        Diesen HTML-Teil erzeugt das Navigationsmodul indem es seine Daten in ein eigenes Template einfügt.

        Das gleiche kannst du mit den anderen Teilbereichen deiner Webseiten machen.

        echo "$verabschiedung $name";

        1. Hi echo "$name";

          Ich frag mich manchmal woher ihr das Wissen her habt!?
          Links? Bücher?

          Gruß
          Torsten

          1. echo $begrueszung;

            Ich frag mich manchmal woher ihr das Wissen her habt!?
            Links? Bücher?

            Ja, in meinem Fall ist das so. Dazu kommt noch jahrelange Erfahrung und das Erlernte aus eigenen Fehlern [1]. Vor allem ist es meiner Meinung nach wichtig, die Ursache der Fehler zu erforschen und zu verstehen, was verkehrt läuft.

            Übrigens, wenn du noch eine Meinung von mir haben möchtest: Versuche erst einmal unabhängig von dem Werkzeugen (PHP, Smarty, ...) eine generische Lösung zu skizzieren. Gute Vorbereitung ist schon der halbe Erfolg.

            Und noch ein Vorschlag zum Thema Werkzeug: In der c't 03/2005 gibt es auf der Seite 194 eine Vorstellung des Template-Systems TAL (leider nicht online)(weitere Stichwörter zum Füttern einer Suchmaschine sind TALES, METAL und Zope (für Zope wurde es enwickelt)). Ich habe mich mit diesem System zwar noch nicht intensiv beschäftigt, halte es aber für ein sehr sinnvolles. Eine Implementation in PHP gibt es auf http://phptal.motion-twin.com/, aber auch diese kenne ich (noch) nicht.

            echo "$verabschiedung $name";

            [1] Damit will ich nicht sagen, dass ich mittlerweile fehlerfrei wäre. Das zu behaupten habe ich nich vor, solange ich lebe. (Das klingt sehr pathetisch und vielleicht stellt sich in der Zukunft heraus, dass ich mich diesmal auch geirrt habe... :-)

    4. Hallo Christof,

      if ($_GET['page']=="") {
          $page="start.htm;

      Der String »start.htm« sollte aber auch wieder geschlossen werden ...

      $handle = fopen ($page, "r");
      $contents = fread ($handle, filesize ($page));
      fclose ($handle);

      du kennst aber schon fetch(), oder?

      Grüße aus Nürnberg
      Tobias

  4. Hallo Torsten,

    Dieses Projekt möchte ich jetzt in ein CMS umbauen. [...] Ich habe mich für Smarty entschieden

    Da hast du was verwechselt - Smarty hat mit einem CMS (Content Management System) zu tun. Mit Smarty kannst du zwar den Code vom Design trennen - ein CMS-System ist das dann aber trotzdem noch nicht ...

    Wie man diese Navigation in Smarty macht würde ich mich über etwas Beispiel-Code sehr freuen.

    ich schreibe jetzt einfach mal wie ich das mache :-)

    Die Datei die aufgerufen wird, wenn man example.com aufruft enthält lediglich diesen Code:

    <?php  
    $seite = 1;  
    $tmpl->assign('inh',$tmpl->fetch('tmpl.0.index.inc.html'));  
    $tmpl->assign('titel','Titel der Seite');  
    ?>
    

    hier wird also lediglich eine Seitennummer gesetzt (ist für die Navigation nötig, s.u.), der Inhalt der Seite und der Titel der Seite in eine Template-Variabel geschrieben. Die die Generierung des Inhaltes kann natürlich auch wesentlich aufwendiger sein, wenn z.B. Formulare verarbeitet werden o.ä. Für den Titel habe ich inzwischen auch schon eine Funktion für Smarty geschrieben die den Titel anhand der Seitennummer generiert.
    Bevor dieser Code ausgeführt wird, wird aber noch die Datei die mit hilfe von auto_prepend_file geladen wird:

    <?php  
    error_reporting(E_ALL);  
    require_once('conf/pfade.inc.php');  
    require_once(SMARTY_PFAD.'Smarty.class.php');  
    require_once('func/prueferechte.inc.php');  
    $tmpl = new Smarty;  
    $tmpl->template_dir = TMPL_DIR;  
    $tmpl->compile_dir  = TMPLC_DIR;  
    $tmpl->[link:http://smarty.php.net/manual/de/api.register.function.php@title=register_function]('pruefeRechte','pruefeRechte');  
    ?>
    

    hier werden also die Einstellungen und Smarty geladen, sowie Smarty "gestartet". Außerdem lassen sich hier auch Funktionen in Smarty übergeben oder eine Datenbankverbindung öffnen.

    Nach dem Abarbeiten des eigentlichen Scriptes wird dann noch die in auto_append_file angegebene Datei ausgeführt:

    <?php  
    $tmpl->assign('s',$seite);  
    $inh = $tmpl->fetch('tmpl.inc.html');  
    echo $inh;  
    ?>
    

    Hier wird im Prinzip also lediglich Seitenzahl an Smarty übergeben und as Template tmpl.inc.html eingelesen. Dieses Template sieht so aus:

    <!DOCTYPE [...]>  
    <html>  
    <head>  
    <title>{$titel}</title>  
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />  
    <link rel="shortcut icon" href="/src/img/favicon.ico" />  
    <style type="text/css">  
    [code lang=css]@import url("/src/css/screen.css");
    

    {$css_inline}
    </style>
    </head>
    <body{if isset($onload)} onload="{$onload}"{/if}{if isset($bodyid)} id="{$bodyid}"{/if}>

    {if $navweg != 1}<div id="nav">{include file="tmpl._navigation.inc.html"}</div>{/if}

    <div id="inh">{$inh}</div>
    </body>
    </html>[/code]

    • außer vielleicht der if-Abfragen nichts besonderes - interessant wird es lediglich innerhalb von <div id="nav"> - hier wird das Template für die Navigation eingebunden:
    {[link:http://smarty.php.net/manual/de/language.custom.functions.php#language.function.assign@title=assign] var=a value=' class="aktuell"'}  
    <ul id="nav">  
     <li{if $s == 1}{$a}{/if}><a href="{$pfad}">Startseite</a></li>  
     <li{if $s == 2}{$a}{/if}><a href="{$pfad}fachbereich/">Fachbereich</a>  
     {if substr($s,0,1) == 2}  
     <ul>  
      <li{if $s == 21}{$a}{/if}><a href="{$pfad}fachbereich/was_ist_wt/">Was ist WT?</a></li>  
      <li{if $s == 24}{$a}{/if}><a href="{$pfad}fachbereich/geschichte.html">Geschichte des FB</a></li>  
     </ul>  
     {/if}  
     </li>  
    </ul>
    

    (das ist eine Ausschnitt der Navigations-Datei von http://www.fh-nuernberg.de/wt/) Hier sieht man für was die Variable $seite ist - anhand dieser wird entschieden, welches der aktuelle Menüpunkt ist, und welche Untermenüpunkte eingebunden werden sollen.

    Alle Klarheiten beseitigt?

    Grüße aus Nürnberg
    Tobias

    1. Hi Tobias,

      erstmal danke für die Mühe.
      Es gibt also doch noch Pragmatiker und vorallem Hilfsbereite Menschen in diesem Forum. Werde mir das morgen mal in Ruhe anschauen, bin jetzt zu müde dazu. Vielen Dank

      Gruß
      Torsten