echo $begrüßung;
Auf Wunsch folgt die Serverseite auch noch mal als PHP-Version.
Als nächstes, ganz im Sinne meines älteren Beitrags, eine komplett serverseitig generierte Bildergalerie. Hier übernimmt ein Perl-Skript die Aufgaben: [...]
Ein Teil des Galerie-Scripts. Das Template ist das selbe wie bei der Perl-Variante.
<?php
// Minimal benötigte PHP-Version: 4.3.0
#error_reporting(E_ALL);
require_once 'common.php';
// Dateiname der Template-Datei, relativ zu diesem Script oder absolut angeben.
define('TEMPLATE_FILENAME', 'gallery.tpl');
// URL zu diesem Script
define('SCRIPT_URL', $_SERVER['SCRIPT_NAME']);
// SCRIPT_URL enthält beispielsweise /gallery2.php
// PHP-Fehlermeldungstext in $php_errormsg schreiben lassen
ini_set('track_errors', 1);
/**
* Erstellt aus dem Template die HTML-Ausgabe.
*
* @param string $templateFilename Dateiname der Template-Datei
* @param array $images Array mit Bildinformation
* @param string $galleryDirectory Galerie-Verzeichnis relativ zum Basis-Verz.
* @param string $showImageFilename Dateiname des anzuzeigenden Bildes
* @return string
*/
function createHtmlFromTemplate($templateFilename, $images, $galleryDirectory, $showImageFilename) {
if (false === $template = @file_get_contents($templateFilename)){
error('Template nicht gefunden', $php_errormsg);
return '';
}
$href = sprintf('%s?%s=%s', SCRIPT_URL, URL_PARAMETER_NAME, $galleryDirectory);
$galleryDirectory = trim(GALLERY_BASE_DIRECTORY, '/') . '/' . trim($galleryDirectory, '/') . '/';
$templateLoopPattern = '#<TMPL_LOOP +NAME=THUMBS>(.*?)</TMPL_LOOP>#s';
if (preg_match_all($templateLoopPattern, $template, $matches)) {
$replacements = array();
foreach ($matches[1] as $nr => $match) {
foreach ($images as $imageFilename => $imageInfo) {
$templateLoopVars = array(
'<TMPL_VAR NAME=SCRIPT>' => $href . $imageFilename,
'<TMPL_VAR NAME=THPATH>' => $galleryDirectory . getThumbnailFilename($imageFilename),
'<TMPL_VAR NAME=PICNAME>' => basename($imageFilename),
);
$replacements[$nr][] = strtr($match, $templateLoopVars);
}
}
foreach ($replacements as $replacement)
$template = preg_replace($templateLoopPattern, implode('', $replacement), $template, 1);
}
$templateVars = array(
'<TMPL_VAR NAME=PICNAME>' => $showImageFilename,
'<TMPL_VAR NAME=DIRPATH>' => $galleryDirectory,
);
$template = strtr($template, $templateVars);
return $template;
}
// Wurde ein Dateiname statt eines Verzeichnisses angegeben?
if (is_file(REAL_GALLERY_DIRECTORY)) {
// Dateiname und Verzeichnis trennen
$showImageFilename = basename(REAL_GALLERY_DIRECTORY);
$realGalleryDirectory = dirname(REAL_GALLERY_DIRECTORY);
} else
$realGalleryDirectory = REAL_GALLERY_DIRECTORY;
if (!is_dir($realGalleryDirectory))
error('Galerie-Pfad ist kein Verzeichnis', $realGalleryDirectory);
// Galerie-Basis-Pfad aus Galerie-Verzeichnis entfernen.
if (strpos($realGalleryDirectory, REAL_GALLERY_BASE_PATH) === 0)
$galleryDirectory = rtrim(substr($realGalleryDirectory, strlen(REAL_GALLERY_BASE_PATH)), '/') . '/';
else
trigger_error('Galerie-Verzeichnis außerhalb des DocumentRoot.', E_USER_ERROR);
// Wenn dieser Fehler ausgelöst wird, muss ein Zugriffsscript für die
// Bilddateien erstellt werden. Außerdem müssen einige Anpassungen bezüglich
// der Pfad-Ermittlung in diesem Script vorgenommen werden. Dies zu tun
// obliegt dem (fortgeschrittenen) Anwender.
// $galleryDirectory enthält beispielsweise default/
// Array mit Bilddateinamen und -informationen anlegen
// $images = array(filename => imageInformation, ...)
$images = array();
// Alle Dateien auf Bildinhalt testen
foreach (glob($realGalleryDirectory . '/*', GLOB_NOSORT) as $filename)
// Wenn $filename kein Bild ist, erzeugt getimagesize() neben dem vom if
// berücksichtigten Rückgabewert false auch noch eine unerwünschte
// Notice-Meldung, die mit dem Fehlerkontrolloperator @ unterdrückt wird.
if ($imageInfo = @getimagesize($filename))
$images[basename($filename)] = $imageInfo;
// "natürliches" Sortieren nach Dateinamen:
// a1, a2, ..., a9, a10, ... statt a1, a10, a2, ...
uksort($images, 'strnatcmp');
// Alternativen:
// uksort($images, 'strnatcasecmp'); // Groß-/Kleinschreibung ignorieren
// ksort($images); // "ASCIIbetisches" Sortieren
if (!isset($showImageFilename)) {
reset($images);
$showImageFilename = key($images);
}
// Erzeuge die HTML-Seite aus dem Template.
echo createHtmlFromTemplate(TEMPLATE_FILENAME, $images, $galleryDirectory, $showImageFilename);
Dazu gibt es eine Datei namens common.php. Sie enthält Dinge, die vom obigen Galerieanzeigescript benötigt werden als auch vom Thumnailerstellungsscript.
<?php
if (!isset($_SERVER['DOCUMENT_ROOT'])) {
define('DOCUMENT_ROOT', '/data/wwwdocs/_test/picgal');
// Nicht alle Webserver stellen DOCUMENT_ROOT zur Verfügung.
#trigger_error('DOCUMENT_ROOT nicht vorhanden, bitte Konstante setzen', E_USER_ERROR);
#define('DOCUMENT_ROOT', '...');
} else
define('DOCUMENT_ROOT', rtrim($_SERVER['DOCUMENT_ROOT'], '/'));
// DOCUMENT_ROOT enthält beispielsweise /pfad/zum/docroot
// Pfad zu den Galerien, relativ zum Galerie/Thumbnail-Script oder absolut angeben.
define('GALLERY_BASE_DIRECTORY', 'galleries');
// Nimm dies, wenn kein Galerie-Verzeichnis übergeben wurde
define('DEFAULT_GALLERY_DIRECTORY', 'default');
#define('DEFAULT_GALLERY_DIRECTORY', 'roadster/urlaub_2004');
// Name des Parameters zur Scriptsteuerung
define('URL_PARAMETER_NAME', 'path');
// Verzeichnis der Thumbnails, relativ zum jeweiligen Galerie-Verzeichnis
define('THUMBNAILS_DIRECTORY', 'thumbs');
// Thumbnail-Dateinamen-Vorspann und -Anhängsel.
define('THUMBNAIL_PREFIX', 'tn_');
define('THUMBNAIL_SUFFIX', '');
// Vollen Pfadnamen zum die Galerien enthaltenen Verzeichnis ermitteln
// und einen(!) / anhängen
define('REAL_GALLERY_BASE_PATH', rtrim(realpath(GALLERY_BASE_DIRECTORY), '/') . '/');
// REAL_GALLERY_BASE_PATH enthält beispielsweise /pfad/zum/docroot/galleries/
// Vollen Pfadnamen zur gewünschten Galerie ermitteln
define('REAL_GALLERY_DIRECTORY', isset($_GET[URL_PARAMETER_NAME]) ?
realpath(REAL_GALLERY_BASE_PATH . trim($_GET[URL_PARAMETER_NAME], '/')) :
// Kein Parameter path übergeben, Default-Galerie verwenden.
REAL_GALLERY_BASE_PATH . trim(DEFAULT_GALLERY_DIRECTORY, '/'));
// REAL_GALLERY_DIRECTORY enthält beispielsweise /pfad/zum/docroot/galleries/default
// Führt der Pfad zu einem Ziel außerhalb von GALLERY_BASE_DIRECTORY?
if (substr(REAL_GALLERY_DIRECTORY, 0, strlen(REAL_GALLERY_BASE_PATH)) != REAL_GALLERY_BASE_PATH)
die('Path violation.'); // Angriffsversuch kurz und schmerzlos beenden.
/**
* Erstellt den Thumbnail-Dateinamen aus einem gegebenen Bilddateinamen.
*
* @param string $imageFilename
* @return string
*/
function getThumbnailFilename($imageFilename) {
$extension = pathinfo($imageFilename, PATHINFO_EXTENSION);
return trim(THUMBNAILS_DIRECTORY, '/') . '/'.
THUMBNAIL_PREFIX .
substr($imageFilename, 0, - (strlen($extension) + 1)) . // ohne Extension
THUMBNAIL_SUFFIX .
'.' . $extension;
}
/**
* Bearbeiten von Fehlermeldungen
*
* Bitte Inhalt dieser Funktion ersetzen durch eine angemessene Fehlerbehandlung.
* Anwender sollten weder die Ursache noch Details dazu angezeigt bekommen.
*
* @param string $message
* @param string $details
*/
function error($message, $details = '') {
echo '<div>', $message, ' - ', $details, '</div>';
}
Das Script »gallery2.pl« nutzt das Perl-Modul HTML::Template, um anhand eben eines Templates die Galerie zu generieren.
So etwas ähnliches gibt es für PHP beispielsweise bei PEAR. Da das Template aber sehr einfach gehalten war, hab ich kurzerhand eine Template-Funktion selbst geschrieben.
Was mir auch noch aufgefallen ist: Dein Perl-Script dürfte eine Sicherheitslücke enthalten. Du stellst zwar dem als Parameter übergebenen Pfad zur Galerie ein $ENV{DOCUMENT_ROOT} voran, prüfst aber nicht weiter, ob so etwas wie /../ im Pfad vorkommt. Ich nehme an, opendir verhindert das auch nicht. In meiner PHP-Version lasse ich den realen Pfad auflösen und prüfe den gegen ein konfiguriertes Verzeichnis.
Ebenso ungeprüft ist der Dateiname, der für den Nicht-Javascript-Fall als Parameter übergeben wird. Der muss nur auf gif|jpe?g|png enden und wird dann einfach ins HTML eingefügt.
Eine weitere Ungereimtheit ist, dass für die Thumbnail nur die auf .jpg endenden Dateien berücksichtigt werden.
Verbesserungspotential gibt es noch beim Bildformat. Das ist jetzt für die Thumbnails auf 4:3 festgeklopft. Das könnte man noch als variable Größe ins Template einbauen. Dann müssten auch Hochkant-Bilder nicht mehr "hingelegt" werden und Bilder mit anderen Seitenverhältnissen könnte man ebenfalls berücksichtigen. In dem Fall wäre auch mein Thumbnailerstellungsscript zu überarbeiten.
Die Pfadangaben im Perl-Script könnten auch noch etwas zentraler notiert werden, dann lassen sie sich besser bearbeiten (obwohl das Script aufgrund seiner geringen Größe ja schon recht übersichtlich ist).
echo "$verabschiedung $name";