13.2 Einbindung in die Applikation 

Das Blog wird um die Möglichkeit erweitert, komplette Archive mit Bildern hochzuladen, die dann alle in die Medienbibliothek aufgenommen werden. Um das Schreiben von Archiven zu zeigen, wird es nach diesem Kapitel die Möglichkeit geben, alle Bilder in einem der in Kapitel 12, »Bildverarbeitung«, vorgestellten Formate als Archiv herunterzuladen, um sie lokal zu sichern. [http://de.php.net/stream ] [http://de.php.net/manual/de/wrappers.php ]
Zunächst wird eine Übersichtsseite über die vorhandenen Bilder erstellt, auf der die bereits hochgeladenen Bilder zu sehen sind, und die außerdem einen Zugriff auf das Archiv mit allen Bildern sowie auf die Möglichkeit, neue Bilder einzufügen, bieten soll.
13.2.1 Übersichtsseite 

Die Aktion für die Übersichtsseite wird mit den anderen aus Kapitel 12, »Bildverarbeitung«, bekannten Methoden zur Verwaltung der Mediendateien in der Datei classes/actions/gallery.php definiert. Der dazu verwendete Code sowie die verwendeten Komponenten sind aus den vorigen Kapiteln bekannt und sollen hier nicht weiter erläutert werden. Im Wesentlichen wird eine Liste der Bilder aus dem Verzeichnis mit den Bildern ausgelesen, mit der vorgestellten Komponente ImageAnalysis auf ihre Ausmaße überprüft und dann an ein Template übergeben, das mittels der in Kapitel 8, »Template«, vorgestellten Template-Komponente gerendert wird. Das Resultat ist unter der URL http://gpblog/media zu sehen.
Abbildung 13.1 Galerie mit Bilderübersicht
Es wird eine komplette Liste aller Bilder ausgegeben. Falls die Bilder in einem anderen Format angezeigt werden sollen, kann dieses optional an die URL angehängt werden. So zeigt ein Aufruf der URL http://gpblog/media/medium die Bilder in dem in Kapitel 12, »Bildverarbeitung«, definierten, mittelgroßem Format.
13.2.2 Archiv erstellen 

Um den Verweis zum Bildarchiv herunterladen in obigem Screenshot mit Leben zu füllen, wird eine weitere Aktion in der Datei classes/actions/gallery.php eingefügt. Diese Aktion soll ausgeführt werden, wenn die Aktion archive_media aufgerufen wird. Dazu wird diese Aktion entsprechend der Struktur der Applikation, die in Kapitel 3, »Die Applikationsbasis«, beschrieben wurde, in der Methode registerSlots() in der gleichen Datei eingefügt.
gpBlogController::getInstance()->actionSignals->connect(
"archive_media",
array( __CLASS__, "archive" )
);Listing 13.1 Signal zur Archivierung
Anschließend muss noch noch die Methode archive() in dieser Klasse mit Inhalt gefüllt werden. Der Besucher soll selbst entscheiden, in welchem Format er die Bilder herunterladen will, wozu zu Beginn über die aus Abschnitt 3.2.1, »Url«, bekannte Url-Komponente ein optionaler Parameter mit der Größe ausgelesen wird.
$config->addOrderedParameter( 'size' );
$url->applyConfiguration( $config );
$size = ( $url->getParam( 'size' ) !== null ) ?
$url->getParam( 'size' ) :
'original';Listing 13.2 Parameterverarbeitung
Als Standardwert werden die Bilder in Originalgröße in das Archiv gepackt. Über eine URL wie http://gpblog/archive_media/thumb können die Bilder optional in anderen Größen angefordert werden.
$files = array();
foreach ( self::$fileExtMap as $extension )
{
$files = array_merge(
$files,
glob( dirname( __FILE__ ) .
"/../../uploads/*_{$size}.{$extension}" )
);
}Listing 13.3 Relevante Dateien auslesen
In dem Verzeichnis upload/ im Applikationswurzelverzeichnis, in dem in Kapitel 12, »Bildverarbeitung«, die Mediendateien abgelegt worden sind, wird nach allen relevanten Bildern gesucht. Dazu wird über das zuvor definierte Array mit validen Dateiendungen iteriert, und alle Dateien in der angeforderten Größe mit der aktuellen Dateiendung werden dem Array mit den zu packenden Dateien $files hinzugefügt. Die PHP 5-Funktion glob() [http://php.net/glob ] akzeptiert dabei einfache reguläre Ausdrücke, wie Sie sie von der Shell gewöhnt sind, und liefert ein Array mit passenden Dateien zurück, das dann über array_merge() [http://php.net/array_merge ] mit den bisher gefundenen Dateien kombiniert wird.
// Create archive with all images
$archive = ezcArchive::open(
$archiveFile = dirname( __FILE__ ) .
'/../../cache/blog_images.zip',
ezcArchive::ZIP
);
$archive->truncate();
$archive->append(
$files,
dirname( __FILE__ ) . "/../../uploads/"
);
$archive->close();
// Send archive to user
header( 'Content-Type: application/zip' );
readfile( $archiveFile );Listing 13.4 Neues Archiv erstellen
Zu Beginn wird eine Datei mit der Endung .zip geöffnet, was nicht relevant für den Dateityp ist. Dieser wird für bislang nicht existierende Dateien über den zweiten Parameter der statischen Methode ezcArchive::open() definiert. Bei bereits existierenden Archiven, an die Dateien angehängt werden, kann auf diesen Parameter verzichtet werden. Es folgt eine Liste der unterstützten Archivtypen:
|
ezcArchive::BZIP2 |
BZIP2 compression format |
|
ezcArchive::GZIP |
Gnu ZIP compression format |
|
ezcArchive::TAR |
Normal tar archive |
|
ezcArchive::TAR_GNU |
GNU tar archive |
|
ezcArchive::TAR_PAX |
PAX tar archive |
|
ezcArchive::TAR_USTAR |
USTAR tar archive |
|
ezcArchive::TAR_V7 |
Tar version 7 archive |
|
ezcArchive::ZIP |
ZIP archive |
Da in dem obigen Beispiel immer dieselbe Datei für das herunterzuladende Archiv verwendet wird, ist das Archiv zu leeren, bevor erneut alle Dateien hinzugefügt werden. Dies geschieht über die Methode truncate(), die das Archiv vollständig leert. Anschließend können die zuvor in dem Array $files gesammelten Dateien über die Methode append() dem Archiv hinzugefügt werden. Der zweite Parameter entspricht dabei dem Basispfad der Dateien, die in das Archiv eingefügt werden, damit Sie diese später nicht in tief verschachtelten Unterverzeichnissen im Archiv auffinden, sondern im Wurzelverzeichnis.
Nachdem alle Dateien eingefügt worden sind, kann die Archivdatei geschlossen und an den Browser geschickt werden. Kombiniert mit dem korrekten MIME-Type für die Datei, sollte sich damit eine mit jedem Betriebssystem einfach zu verwendende Datei mit allen hochgeladenen Bildern auf der Festplatte des Besuchers finden.
Um das Beispiel einfach zu halten, wurden einige Betrachtungen, die in einer produktiv eingesetzten Applikation relevant sind, nicht beachtet. Da es passieren kann, dass mehrere Benutzer gleichzeitig auf ein Archiv zugreifen wollen, müsste das Archiv in einer temporären Datei erstellt werden.
Um die Last der Applikation zu reduzieren, sollten neue Bilder an das Archiv angefügt werden, anstelle bei jeder Anfrage das Archiv vollständig neu zu generieren. Der folgende Abschnitt gibt ein Beispiel, wie das mit der Archive-Komponente zu machen ist.
13.2.3 Dateien an ein Archiv anhängen 

Die neuen Dateien könnten beim Hochladen der Dateien direkt an das Archiv angehängt werden, doch werden Sie, falls Sie die Applikation selbst getestet haben sollten, bemerkt haben, dass das Erzeugen der Archive ein wenig Zeit in Anspruch nimmt, was das Einstellen neuer Mediendateien nicht verzögern sollte. Auf Basis des im letzten Beispiel erstellten Arrays mit den Bilddateien wird im folgenden Beispiel überprüft, welche Dateien bereits im Archiv vorhanden sind. Die anderen werden angehängt.
$basepath = dirname( __FILE__ ) . "/../../uploads/";
$files = array();
foreach ( self::$fileExtMap as $extension )
{
$files = array_merge(
$files,
glob( $basepath . "*_{$size}.{$extension}" )
);
}Listing 13.5 Relevante Dateien auslesen
Zu Beginn wird das Array mit den Bilddateien in der angefragten Größe erstellt. Durch die neue Trennung vom Pfad $basepath, in dem die Bilder liegen, wird später ein Vergleich mit den Bildern, die sich bereits im Archiv befinden, leichter fallen.
// Check files, which are already in archive
$archive = ezcArchive::open( 'blog_images.zip' );
$archiveFiles = array();
foreach ( $archive as $entry )
{
$archiveFiles[] = $entry->getPath();
}Listing 13.6 Dateien aus dem Archiv auslesen
Im nächsten Schritt wird die Liste der sich bereits im Archiv befindlichen Dateien ausgelesen. Dazu kann über das Archiv iteriert werden. Im Objekt $entry der Klasse ezcArchiveEntry befindet sich ein Verweis auf die Datei im Archiv. Hier interessiert allein der Pfad, um diesen mit den hochgeladenen Dateien zu vergleichen. Daher wird er im Array $archiveFiles gespeichert.
Das ezcArchiveEntry stellt erheblich mehr Informationen über die Datei aus dem Archiv zur Verfügung, die in diesem Fall nicht relevant sind. So können Sie über die Methoden der Klasse auf Benutzer, Zugriffsrechte, Änderungszeiten und den Dateityp zugreifen, falls diese Angaben für Ihre Applikation relevant sind.
// Create array with yet missing files
$missing = array_diff( $files, $archiveFiles );
// Add missing files to archive
foreach ( $missing as $file )
{
$archive->append( $basepath . $file, $basepath );
}
$archive->close();Listing 13.7 Fehlende Dateien in das Archiv einfügen
Die PHP-Funktion array_diff() [http://php.net/array_diff() ] gibt die Differenz der beiden Arrays mit den Dateinamen zurück, sodass $missing die im Archiv fehlenden Dateien enthält. Diese können entweder (wie im vorigen Beispiel) durch Übergabe aller Dateien in einem Array oder durch das einzelne Einfügen der Dateien (wie in diesem Beispiel) an das Archiv angehängt werden. Das resultierende Archiv enthält nun alle Mediendateien unter Minimierung der dafür benötigten Ressourcen.
13.2.4 Archive auslesen 

Als Nächstes soll es erleichtert werden, mehrere Bilder gleichzeitig hochzuladen. Lediglich mehrere Eingabefelder zu verwenden, kommt aufgrund der Bedienungsunfreundlichkeit für den Benutzer nicht in Frage. Entsprechend wird die Methode aus Kapitel 12, »Bildverarbeitung«, die bislang nur Bilder als hochgeladene Dateien akzeptierte, um das erfolgreiche Behandeln von Archiven erweitert. Das Formular findet sich unter der URL http://gpblog/create_media oder hinter dem Link Eine Mediendatei zur Galerie hinzufügen in der Übersicht. Beim Absenden des Formulars wird über die Aktion save_media die Methode save() in der Datei classes/actions/gallery.php aufgerufen, die im folgenden Beispiel erweitert wird.
// Try to open uploaded file as an archive
try
{
$archive = ezcArchive::open( $_FILES['medium']['tmp_name'] );
foreach ( $archive as $entry )
{
$archive->extractCurrent(
$cacheFolder = dirname( __FILE__ ) .
'/../../cache/archive'
);
}
// Handle files
}
catch ( Exception $e )
{
// Just progress and try to open as normal image
}Listing 13.8 Hochgeladene Datei als Archiv behandeln
Es wird nun versucht, die Datei, die zuvor direkt an die statische Methode processImages() weitergegeben wurde, in der Annahme, dass es sich um ein Bild handelt, mit der Archive-Komponente zu öffnen. Falls der Versuch nicht erfolgreich ist, wird wie zuvor fortgefahren und die hochgeladene Datei als Bild verarbeitet.
Wie aus dem vorigen Absatz bekannt ist, kann ein Archiv gelesen werden, indem mit foreach() über dieses iteriert wird. In diesem Beispiel wird allerdings nicht nur der Pfad der im Archiv enthaltenen Datei ausgelesen, sondern diese werden direkt in ein temporäres Verzeichnis cache/archive zur weiteren Verarbeitung entpackt.
// Process all images in archive folder
foreach( ezcFile::findRecursive(
$cacheFolder,
array(),
array( '@/.svn/@' )
) as $file ) {
// ...
}Listing 13.9 Extrahierte Dateien suchen
Da die Dateien in einem Archiv auch in Unterverzeichnissen vorkommen können, hilft hier die Methode ezcFile::findRecursive() aus der File-Komponente weiter. Mit ihr lassen sich Dateien auch in Unterverzeichnissen finden, wobei der erste Parameter den zu durchsuchenden Pfad enthält, der zweite Parameter eine Liste von Kriterien, die eine gefundene Datei erfüllen muss, um in der Ergebnisliste aufzutauchen, und der dritte Parameter eine Liste von Kriterien, die zum Ausschluss der gefundenen Datei aus der Ergebnisliste führt.
Da das Projekt in einem SVN-Repository verwaltet wird, werden in dem Beispiel alle SVN-eigenen Dateien, die in einem Unterverzeichnis .svn/ liegen, ausgeschlossen. Die so extrahierten und gefundenen Dateien können anschließend wie bekannt weiterverarbeitet werden.
try
{
self::processImage( $file, basename( $file ) );
}
catch ( Exception $e )
{
// Just continue to next file, if one could not be
// processed.
}
// Remove all processed images
unlink( $file );Listing 13.10 Bilder verarbeiten
Der einzige Unterschied zum vorigen Kapitel ist die Behandlung von Exceptions aus der Methode self::processImage(). Da es durchaus akzeptabel scheint, wenn auch Dateien in dem Archiv enthalten sind, die nicht als Bild verarbeitet werden können, werden die Exceptions einfach ignoriert. Zum Abschluss wird die verarbeitete Datei gelöscht, da sie sich im Falle einer erfolgreichen Verarbeitung nun im Verzeichnis uploads/ befindet.
// Show gallery with all new uploaded images
$url->setParam( 'action', 'media' );
gpBlogController::getInstance()->mainSignals->emit(
'redirect',
$url
);Listing 13.11 Galerie mit neuen Bildern anzeigen
Da eine Anzeige aller Dateien in allen verfügbaren Größen bei potentiell vielen Dateien in einem Archiv nicht mehr zweckgemäß erscheint, wird zurück zur Übersichtsseite weitergeleitet, wenn das Archiv erfolgreich verarbeitet wurde. Dort sollten nun auch die neu hochgeladenen Bilddateien zu sehen sein.





Ihre Meinung






