PHP/Tutorials/Templates/Dateien mit include nachladen

Aus SELFHTML-Wiki
< PHP‎ | Tutorials‎ | Templates
Wechseln zu: Navigation, Suche

In diesem Tutorial lernen Sie, wie Sie immer wiederkehrende Elemente Ihrer Webseiten, wie Navigation, Seitenkopf <header> und die Fußzeile <footer> in eigene Dateien auslagern können, die Sie dann problemlos einbinden können. Änderungen, wie das Einfügen eines Links zu einer neuen Seite, müssen dann nur einmal zentral erledigt werden.

Gerade bei mittelgroßen Webprojekten kann die ständige Aktualisierung zahlreicher Seiten hohen Arbeitsaufwand bedeuten. Alternativ käme der Einsatz eines CMS in Frage.

Kann mein Webspace PHP?[Bearbeiten]

Heutzutage ist PHP Standard bei allen Providern. Sie können dies einfach testen, indem Sie folgendes Programm auf ihren Server laden.

Beispiel: phpinfo.php
<?php
  phpinfo();
Folgt nach dem PHP-Programmcode kein auszugebender HTML-Code mehr, so kann das schließende ?> fehlen.

Falls PHP installiert ist, gibt Ihnen dieses kleine Programm sehr viele Informationen über ihre PHP-Installation und den Webserver aus, was recht nützlich ist. Merken Sie es sich also gut.

Screenshot der Ausgabe von phpinfo() in PHP 7.1

Allerdings kann es sein (und ist nicht wirklich selten!), dass Webhoster in dem (fragwürdigen) Glauben, hierdurch die Sicherheit der Installation zu erhöhen, die Abarbeitung der Funktion phpinfo() verbieten. In dem Fall testen Sie mit:

Beispiel: phptest.php
<?php echo 'PHP? Funktioniert! Version ist: ', phpversion(), "\n";

Wird etwas wie: PHP? Funktioniert! Version ist: 7.1.0 ausgegeben, dann ist PHP ganz offensichtlich tätig geworden, also installiert und konfiguriert.

Auslagern von Seitenkopf und Navigation[Bearbeiten]

Als Beispieldatei verwenden wir unsere Webseite aus dem HTML5-Tutorial.

Da der head neben dem Seitentitel auch weitere Metaangaben hat, die für jede Seite unterschiedlich sein sollen, schneiden wir nur den <header> aus unserem Dokument aus und speichern ihn als header.php ab:

Beispiel: ausgelagerte Navigation in header.php
<header>
  <img src="logo.gif" alt="logo">
  <h1>Titel</h1>
  <nav>
    <ul>
      <li><a href="#link_1.html">Wiki</a></li>
      <li><a href="#link_2.html">Blog</a></li>
      <li><a href="#link_3.html">Forum</a></li>
    </ul>
  </nav>
</header>

Mit dem Footer können wir genauso verfahren.

Einbinden in unsere Webseite[Bearbeiten]

Beispiel: webseite.php
<!doctype html> <head> <meta charset="utf-8"> <title>Meine erste HTML5-Seite</title> </head> <body> <?php include ("header.php"); ?> <main> <article> <h1>Überschrift</h1> <p>Dies ist meine erste HTML5-Seite</p> ... mehr Inhalt </article> <aside> <h2>Weiterführende Links</h2> <ul> <li><a href="#link_1.html">Wiki</a></li> <li><a href="#link_2.html">Blog</a></li> <li><a href="#link_3.html">Forum</a></li> </ul> </aside> </main> <?php include ("footer.php"); ?> </body> </html>

Anstelle der ausgeschnittenen Code-Abschnitte fügen wir jeweils ein include() ein, das die jeweilige Datei aufruft. Damit der PHP-Befehl erkannt und ausgeführt wird, müssen wir unsere HTML-Datei in index.php umbenennen. Die includierten Daten müssen nicht die Endung .php haben, diese ist völlig beliebig! Die Dateien sollten die Endung .php aber durchaus haben, wenn es Dateien sind, die php-Code enthalten – allein schon weil gute Editoren dann das Syntax-Highlighting entsprechend einschalten. Dann bietet sich ggf. zur Klarheit auch die Kombination mehrerer Endungen an, z. B. datei.inc.php. Wenn in den includierten Dateien PHP-Code vorkommt, dann muss dieser auch als PHP-Code markiert sein. Also das öffnende <?php und ggf. schließende ?> enthalten.

Verzeichnisstruktur bei der Verwendung von Includes

Von außen sieht niemand, dass die Navigation aus einer ausgelagerten Datei stammt, da der Browser nur den ihm gelieferten HTML-Code zu Gesicht bekommt und darstellt.

Beachten Sie: Während Sie HTML-Dateien einfach von Ihrer Festplatte aus öffnen können, benötigen Sie für PHP-Dateien einen PHP-Interpreter auf einem Webserver. Sie können auch auf Ihrem Computer einen solchen Webserver einrichten.

Die Alternativen include, include_once, require, require_once - Regeln zur Verwendung[Bearbeiten]

  • include benutzen Sie, wenn Sie eine Datei (womöglich) mehrfach einbinden wollen und PHP die Verarbeitung des Skriptes nicht abbrechen soll, falls diese Datei nicht vorhanden ist. Ist die Datei nicht vorhanden wird allerdings eine Notiz „geworfen“, welche man mit sinnvollen Einstellungen des Error-Reportings unterbinden kann.
  • include_once benutzen Sie, wenn Sie eine Datei genau einmal einbinden wollen und wenn PHP die Verarbeitung des Skriptes nicht abbrechen soll, falls diese Datei nicht vorhanden ist. Einen Versuch, die Datei mehrfach einzubinden, wird PHP schweigend (also ohne Fehlermeldung oder Notiz) übergehen. Ist die Datei nicht vorhanden wird allerdings eine Notiz „geworfen“, welche man mit sinnvollen Einstellungen des Error-Reportings unterbinden kann.
  • require benutzen Sie, wenn Sie eine Datei (womöglich) mehrfach einbinden wollen und wenn PHP die Verarbeitung des Skripts definitiv mit einem Fehler abbrechen soll, wenn diese Datei nicht vorhanden oder nicht lesbar ist.
  • require_once benutzen Sie, wenn Sie eine Datei genau einmal einbinden wollen und wenn PHP die Verarbeitung des Skripts definitiv mit einem Fehler abbrechen soll, wenn diese Datei nicht vorhanden oder nicht lesbar ist. Einen Versuch, die Datei mehrfach einzubinden, wird PHP schweigend (also ohne Fehlermeldung oder Notiz) übergehen.

Beispiele:[Bearbeiten]

include('datei')[Bearbeiten]

include wird gerne genutzt, um wiederkehrende Abschnitte einzubinden. Das Szenario ist folgendes. Ein Benutzer darf z. B. Dateien mit dem Namen produktversion.VERSION.inc.php bearbeiten, damit nicht etwa ein (teurer) Programmierer inhaltliche Änderungen an der Webseite vornehmen muss. Eine der vorgesehenen Dateien existiert aber (noch) nicht:

Beispiel: produktversion.0815.inc.php
<?php
$P_titel = "Toller Teppich";
$P_descr = "Diesen tollen Teppich können Sie nach Belieben ein- oder ausrollen.";
Beispiel: produktversion.0815-rot.inc.php
<?php
$P_titel = "Toller roter Teppich";
$P_descr = "Diesen tollen roten Teppich können Sie nach Belieben ein- oder ausrollen.";


In der includierenden PHP-Datei sieht das dann so aus:

Beispiel: include_products.php
<?php
$arVersionen=array('0815', '0815-rot', '0815-gruen');
foreach ($arVersionen as $version) {
   include ('produktversion.' . $version . '.inc.php'); # Hier werden die Variablen überschrieben!
   echo '<h4>', $P_titel, '</h4><p>', $P_descr, '</p>';
}

Da die Datei „produktversion.0815-gruen.inc.php“ nicht existiert, wird einfach schweigend nochmals auf die durch das Inkludieren der Datei „produktversion.0815-rot.inc.php“ gesetzten Variablen zurückgegriffen. Die Notiz (Warnung) kann man ja unterdrücken. Es würde also (es werden nur die Überschriften gezeigt)

  • „Toller Teppich“
  • „Toller roter Teppich“
  • „Toller roter Teppich“

ausgegeben. Manchmal ist das tatsächlich erwünscht. Allerdings sollte nicht verschwiegen werden, dass dieses „Manchmal“ eine recht seltene Ausnahme ist. Und weil das so ist, gibt es mit require() bzw. require_once() andere Lösungen, aber wir sehen uns erst einmal einen sinnvollen Einsatz von include_once() an:

include_once('datei')[Bearbeiten]

Szenario: In einem größeren Projekt werden Informationen verarbeitet und der Programmierer möchte mit Konstanten arbeiten. Es wird weiter ziemlich viel mit includes gearbeitet. Jetzt kann es aber passieren, dass nicht klar ist, ob eine Datei, nennen wir sie „settings.inc“, bereits inkludiert ist und dass das mehrfache Inkludieren zu einem Fehler führt:

Beispiel: settings.inc
<?php
define ('PROJEKTNAME', 'Fehler vermeiden');

Würde man jetzt diese Datei mehrfach inkludieren, dann würde daraus ein Fehler entstehen:

Beispiel: include.php
<?php
include ('settings.inc');
## weiter unten:
include ('settings.inc');

Denn das würde aus Sicht von PHP zu folgendem Resultat führen:

Beispiel: Was der Interpreter daraus macht:
define ('PROJEKTNAME', 'Fehler vermeiden');
## weiter unten:
define ('PROJEKTNAME', 'Fehler vermeiden');

Eine Konstante ist aber eine Konstante und kann ergo im Programmverlauf nur einmal definiert werden! Der Interpreter würde also einen Fehler melden. Deshalb gibt es include_once():

Beispiel: include_once.php
include_once ('settings.inc');
## weiter unten:
include_once ('settings.inc');
echo '<h1>', PROJEKTNAME, '</h1>';

Der Interpreter stellt fest, er soll diese Datei nur dann inkludieren, wenn er das noch nicht getan hat. So ist einerseits (noch nicht ganz, wie wir gleich sehen werden) sicher gestellt, dass die Informationen geladen werden, aber eben auch, dass nicht mehrfach versucht wird, die Konstanten zu definieren. Die Ausgabe wäre im Erfolgsfall:

<h1>Fehler vermeiden</h1>

require('datei') bzw. require_once('datei')[Bearbeiten]

Was aber passiert, wenn durch einen Fehler die angegebene Datei settings.inc nicht existiert oder nicht lesbar ist? Dann gäbe PHP eine Notiz aus:

<h1>PHP Notice: Use of undefined constant PROJEKTNAME - assumed 'PROJEKTNAME' in - on line 2 PROJEKTNAME</h1>

oder, wenn die Notizen z. B. durch error_reporting(0) unterdrückt sind:

<h1>PROJEKTNAME</h1>

PROJEKTNAME soll da nicht stehen! Das ist natürlich ein „Kardinalfehler“ – und da kommt require() bzw. require_once() ins Spiel. Denn require() würde einen Fehler melden und PHP würde die Skriptverarbeitung abbrechen:

Beispiel: require_once.php
require_once ('settings.inc');
## weiter unten:
require_once ('settings.inc');
echo '<h1>', PROJEKTNAME, '</h1>';

PHP Fatal error: require(): Failed opening required 'settings.inc' (include_path='.:/usr/share/php:/usr/share/pear') in - on line 1

require_once() verhindert dann genau so wie include_once(), dass mehrfach (und vergeblich!) versucht wird die Datei zu includieren und damit die Konstante wiederholt zu definieren.

Des Programmierers Bequemlichkeit kann die Sicherheit gefährden![Bearbeiten]

So manchen wird die Möglichkeit, Dateien so einfach einzubinden auf so manche, nur vordergründig gute Idee bringen. Nämlich die, etwas zu schreiben wie:

Beispiel: selbstmord.php
<?php
  include ($_GET['file']);

Sollte das jemandem auffallen - und das wird es, dann dauert es womöglich nur Minuten bis dieser etwas wie das folgende versucht:

http://localhost/selbstmord.php?file=../../../../../etc/passwd

Mit dem Resultat, dass er den Inhalt der Datei /etc/passwd erhält. Und damit auf einem Linux-System eine für ihn wertvolle Datei mit Benutzerinformationen. Solche Angriffsversuche sind nicht etwa selten, sondern tägliches, automatisiert stattfindendes Geschehen und es gibt terabyteweise Benutzernamen/Passwörter und Bankdaten, gestohlen von ziemlich naseweisen Serverbetreibern im Internet, welche beweisen, dass derart grob nachlässig gehandelt wurde.

Sich gegen diesen Angriff absichern[Bearbeiten]

Möglichkeit: Lassen Sie den Angreifer den Name der Datei nicht (vollständig!) bestimmen:

Beispiel: immer_noch_sehr_gefährlich.php
<?php
  include ('./includes/' . $_GET['file'] . '.html');

Jetzt wird vor den übertragenen Wert das Verzeichnis gehängt und ans Ende die Dateiendung '.html'. Das kann aber immer noch nicht erwünscht sein, weil Sie womöglich folgendes nicht wollen:

http://localhost/gefaehrlich.php?file=../gesperrte_dateien/foo

Beachten Sie: Die in $_GET['file'] enthaltenen Daten können so manipuliert sein, dass das Anhängen der Dateiendung keine Wirkung zeigt! Damit gilt das selbe wie schon oben bei include $_GET['file']!
Beachten Sie: Jegliche Daten, die Benutzereingaben enthalten (das Betrifft die superglobalen Arrays $_GET, $POST, $_REQUEST und $_COOKIE), sind grundsätzlich misstrauisch zu behandeln!

Sehr sicher und vergleichsweise einfach: includieren mit vordefinierten Werten[Bearbeiten]

Nutzen Sie der Sicherheit Ihrer Applikation zuliebe die sehr sichere Möglichkeit, die zu includierenden Dateien über eine Liste vorzudefinieren. Dann muss das Skript nur den richtigen Namen der Datei aus dieser Liste heraussuchen. Das ist sehr leicht zu programmieren:

Beispiel: include_nach_wert.php
<?php
## Aufruf mit https://example.org/?f=home
## In der nicht geheimen, aber sicher (ohne Schreibzugriff!) gespeicherten
## Datei 'includes.txt' stehen die möglichen Werte:
define ('INC_TABLE', 'includes.txt');
## So sieht diese z.B. aus:
/*
home
error
links
whatever
*/
## Die Werte aus der Liste müssen später noch mit der Endung ".inc.php" ergänzt
## werden, um die tatsächlich zu inkludierende PHP-Scriptdatei zu adressieren.

## Das Verzeichnis, in welchem diese Dateien stehen:
define ('INC_DIR', __DIR__.'/includes'); # __DIR__ bedeutet "vom Verzeichnis dieses Scripts aus"

# Aufruf:
include_page();
exit;

function include_page () {
  # alle möglichen Werte aus Datei einlesen
  $list = file(INC_TABLE);

  # Standardwert ist die HOME Seite
  $inc = 'home';

  # soll eine bestimmte Seite eingebunden werden?
  if (array_key_exists('f', $_GET)) {

    $inc = 'error'; # sollte die geforderte Seite nicht existieren

    # gewünschte Datei finden
    foreach ($list as $v) {

      $v = trim($v); # möglichen Zeilenumbruch am Ende entfernen

      # ist das die gewünschte Datei?
      if ($v == $_GET['f']) {
        # übernehmen
        $inc = $v;
      }
    }
  }

  # jetzt inkludieren
  include INC_DIR."/$inc.inc.php";
}

Will man keine Textdatei pflegen, in der die möglichen include-Dateien aufgelistet sind, sondern möchte das dynamisch haben, so bietet es sich an, eine Dateinamenskonvention zu verwenden, anhand derer die Liste der zu inkludierenden Dateien jedes Mal vom Programm selbst ermittelt wird:

Beispiel: dynamisches include_nach_wert.php
<?php
/**
 * Namenskonventionen
 *
 * Dateien, die immer inkludiert werden müssen, enden auf .inc.php
 * Dateien, die Seiten darstellen, enden auf .page.php
 *
 * Aufruf einer Unterseite: https://example.org/?f=whatever
 *
 * Alle zu inkludierenden Dateien sind im Unterverzeichnis /includes/ gespeichert.
 */

$includes = glob(__DIR__.'/includes/*.inc.php');

# alle $includes laden
foreach ($includes as $script) {
  include $script;
}

# Seiten finden
$pages = array();

# Liste mit Seiten befüllen
foreach (glob(__DIR__.'/includes/*.page.php') as $p) {

    # Schlüssel für Dateinamen ermitteln ("home" für "home.page.php")
    $v = preg_replace('~(?i)(?:.*/)?([^.]+)\.page\.php$~', '$1', $p);

    $pages[$v] = $p;
}

# anzuzeigende Seite ermitteln
$page = 'home'; # Standard

# soll eine bestimmte Seite eingebunden werden?
if (array_key_exists('f', $_GET)) {

  $page = 'error'; # sollte die geforderte Seite nicht existieren

  # gewünschte Datei finden
  foreach (array_keys($pages) as $p) {

    # ist das die gewünschte Datei?
    if ($p == $_GET['f']) {
      # übernehmen
      $page = $p;
    }
  }
}

# Seite inkludieren
include $pages[$page];
Die PHP-Funktion glob() liefert ein Array mit Dateipfaden (Strings) zurück, auf die das Muster passt. Die Liste der möglichen Seiten ist ein assoziatives Array, dessen Schlüssel die Kurzform des Dateinamens sind (z.B. "home") und dessen Werte die zugehörigen Dateipfade (z.B. /var/www/...../includes/home.page.php").

Weiterführende Informationen[Bearbeiten]