Digitale Bücher im Format EPUB mit PHP selbst erstellen

Gedanken sind nicht stets parat.
Man schreibt auch, wenn man keine hat.
Wilhelm Busch

EPUB-Kurzanleitung; Generator (EPUB 2); Generator (EPUB 3)

Generell gibt es mehrere Möglichkeiten, EPUB mit PHP zu erstellen. Bevorzugt wird man allerdings, wie auch beim hiesigen Generator, die bei PHP bereits verfügbaren Funktionen zur Verwaltung von ZIP-Archiven verwenden wollen, was hier im Folgenden erläutert wird.

Warum überhaupt Bücher dynamisch erstellen?
Eine Anwendungsmöglichkeit besteht sicher darin, ein individuelles Buch für den jeweiligen Leser nach dessen Vorgaben zusammenzustellen, wozu auch individuelle Widmungen gehören oder Buchvarianten, wo man Personennamen, Orte etc an die Angaben des Lesers anpassen möchte, um ein für den Leser persönliches Buch anzubieten. Auch könnte man das Buch vom Leser aus verschiedenen fertigen Segmenten zusammenstellen lassen, nachdem dieser ein Formular mit Vorlieben ausgefüllt hat - so könnte etwa im Bedarfsfalle zwischen tragischem, glücklichem und realistischem Ende einer Geschichte frei gewählt werden.
Wie beim hiesigen Generator ist es natürlich auch eine sinnvolle Anwendung, wenn dem Leser ein Werkzeug angeboten werden soll, um damit ein Buch mit eigenen Inhalten zu erstellen.

Eine andere Möglichkeit wären Bücher, die durchnumeriert sind oder etwa in limitierter Auflage erscheinen, mit dem Namen des Lesers gekennzeichnet sind und diesem eindeutig zugeordnet sind. Dies kann etwa hilfreich sein, wenn eine solche Information nicht offensichtlich im Buch untergebracht wird, um gegebenenfalls Urheberrechtsverletzungen nachverfolgen zu können oder aber Leser im Voraus darauf hinzuweisen, daß dies möglich ist, um gleich der Idee vorzubeugen, daß dieser etwa das Buch gegen die Intention des Autors auf unerwünschten Wegen erneut veröffentlicht.

Die Methode, durch verborgene Einträge eine Buchversion eindeutig identifizierbar zu machen und einer bestimmten Person zuzuordnen, wird auch soziale Rechteverwaltung genannt, im Gegensatz zur Rechteverwaltung durch Kryptifizierung (DRM), bei welcher Inhalte für verschiedene Lesergruppen gezielt unzugänglich gemacht werden, weswegen diese Methode pauschal als mangelhaft abzulehnen ist.
Allerdings hat auch die soziale Rechteverwaltung Nachteile, denn sie ist eher noch einfacher zu umgehen als die Methode des Unzugänglichmachens von Inhalt.
Bei letzterer Methode sind ohnehin bereits viele Leser gezwungen, die Kryptifizierung mit dafür geeigneten Programmen zu beseitigen, um die Inhalte mit denen von ihnen bevorzugten Programmen präsentiert zu bekommen.
Bei der sozialen Rechteverwaltung können böswillige Nutzer hingegen die Identifizierungsmerkmale beseitigen, weil der Inhalt des Buches ja frei zugänglich ist.
Um dem entgegenzuwirken, können oder sollten die Merkmale, auch Wasserzeichen genannt, dann also an verschiedenen Stellen und in verschiedenen Dokumenten im Buch, durchaus auch mit verschiedenen Methoden, untergebracht werden.
Naheliegend sind zunächst einmal Kommentare und nicht direkt dargestellte Element mit Metainformationen, in denen derartige Merkmale als einfacher Text notiert werden können. Es kann zudem vorteilhaft sein, wenn aus dem Inhalt des Merkmals nicht sofort auf die Funktion geschlossen werden kann, wenn ein böswilliger Manipulierer den Quelltext eines Buches untersucht.
Innerhalb von Bildern kann zudem ebenfalls Information versteckt werden. Bei Vektorgraphik etwa kann Information außerhalb des Anzeigebereiches untergebracht werden, aber auch in der Anzeige so klein präsentiert werden oder auch durch andere graphische Elemente verdeckt werden, daß das Merkmal in der Präsentation keinen sichtbaren Effekt hat.
Bei Pixelbildern können einzelne Pixelbereiche minimal verändert werden, so daß durch Differenzbildung mit dem Original das Merkmal oder Wasserzeichen wieder extrahiert werden kann. Wenn Manipulierer allerdings solche Pixelbilder anders komprimieren oder aus anderen Gründen nachbearbeiten, kann das Wasserzeichen schnell verlorengehen.
Auch Vektorgraphiken können natürlich von Manipulierern nachbearbeitet werden oder aber auch in Pixelbilder konvertiert werden, wodurch dann ebenfalls das Merkmal verlorengehen kann.
Insgesamt ist es also technisch immer möglich, solche Merkmale oder Wasserzeichen aus einem Buch wieder zu entfernen, wenn man sie findet. Das Spiel dreht sich also hier vorrangig darum, von der einen Seite die Merkmale gut zu verstecken, von der anderen Seite, alle Merkmale zu finden und zu beseitigen.

Ist es hingegen nur erwünscht, Leser zu zählen, die das Buch herunterladen oder aber auch zu verifizieren, ob der Zugriff berechtigt ist, bietet es sich eher an, das Buch statisch auf dem Dienstrechner in einem nicht öffentlichen Verzeichnis vorzuhalten und darauf nach der Zählung oder Verifizierung mit einem internen temporär eingerichteten symbolischen Verweis auf dem Dienstrechner zu verweisen, um es unter einer individuellen Zufallsadresse zugänglich zu machen, die dann wieder gelöscht wird. Bei kleineren Büchern kann auch direkt ein PHP-Skript aufgerufen werden, welches nach erfolgter Zählung oder Verifizierung das Buch als Antwort ausgibt.
Die dynamische Erstellung des Buches ist nur dann sinnvoll, wenn sich auch bei jedem neuen Aufruf der Inhalt ändern soll.

Die folgenden kurzen Erläuterungen beziehen sich nur auf die bei der Erzeugung des Buches spezifischen Teile eines Skriptes. Vorausgesetzt werden beim Leser Grundkenntnisse in PHP, um die eigentlichen gewünschten Inhalte zu erzeugen, wie auch etwa ein Anforderungsformular an den Leser zu erstellen und die Antwort dann geeignet auszuwerten und eine normale Ausgabe als Antwort zu erstellen.

Variable Inhalte

Variable Inhalte können natürlich wie üblich mit PHP erstellt werden, was bei XML-Formaten keine besonderen Funktionen erfordert. Allerdings sollte der so erstellte Inhalte in einer Zeichenkette abgelegt werden, wenn er nicht anderweitig statisch verwendet werden soll. Bei Pixelgraphik verfügt PHP ebenfalls über geeignete Module, um diese zu erstellen, von daher ist es auch nicht notwendig, dieses hier ausführlich zu erläutern. Diese sind dann ebenfalls am besten in Zeichenketten abzulegen, beziehungsweise, sofern es sich um große Bilder handelt, kann es sinnvoll sein, nach der Erstellung jedes einzelnen Bildes dieses in das ZIP-Archiv zu kopieren, dann die Zeichenkette zu leeren und mit dem nächsten Bild fortzufahren, um den Speicher des Dienstrechners nicht zu überfordern.

Statische Inhalte

Insbesondere Bilder und eventuell auch einige Texte werden vermutlich bereits statisch vorliegen. Diese werden dann einfach fertig auf dem Dienstrechner bereitgestellt und dann im Anforderungsfalle ins Buch integriert.

Das eigentliche Problem für ZIP mit PHP ist allerdings die Forderung, daß die Datei 'mimetype' mit dem Inhalt "application/epub+zip" nicht komprimiert sein darf, dummerweise die ZIP-Funktionen von PHP immer automatisch komprimieren. Die Lösung besteht darin, bereits ein Archiv mit diesem unkromprimierten Inhalt manuell zu erstellen und als Ausgangsdatei bereitzustellen. Andere immer gleiche Inhalte, etwa auch die Datei 'META-INF/container.xml' sollten auch gleich zu diesem Rohling hinzugefügt werden, um das Dienstprogramm nicht unnötig bei dem PHP-Skript mit Aufgaben zu belasten, die man bereits vorher einfach selbst erledigen kann. Ein Beispiel für solch einen Rohling, welcher vom Generator verwendet wird: 'Buch-Rohling'.

ZIP-Archiv erstellen

Soweit der Autor dieses Artikels das verstanden hat (er wäre über andere Informationen per elektronischer Post kurzfristig dankbar), bestehen die ZIP-Funktionen von PHP darauf, auf dem Dienstrechner eine Datei mit dem Archiv anzulegen - zumindest ist es dem Autor bislang nicht gelungen, dies auf eine Zeichenkette umzubiegen. Der Vorteil solch einer Datei auf dem Dienstrechner ist allerdings ohnehin, daß nicht das komplette Buch im Speicher gehalten werden muß.

Jedenfalls empfiehlt es sich, ein Verzeichnis auf dem Dienstrechner anzulegen, in welchem das Archiv angelegt werden soll. Je nach Konfiguration des Dienstprogrammes kann es notwendig oder aber empfehlenswert sein, für dieses Verzeichnis die Lese- und Schreibrechte geeignet zu wählen, also zumeist lesen, schreiben und ausführen für alle erlauben.

Da es sich um individuell erstellte Bücher handeln soll, kann ein geeigneter Name für das zu erstellende Buch gewählt werden, entweder per Zufallszeichenkette oder mit Zeitinformation darin. Nach Gebrauch und Auslieferung an den Leser sollte dies Buch dann wieder gelöscht oder unzugänglich gemacht werden.
Der Name stehe jedenfalls für folgende Erläuterungen in der Variable $zip_name (einschließlich des Verzeichnisnamens).

Ist der Buch-Rohling verfügbar, so wird als nächster Schritt dieser Buch-Rohling in das genannte Verzeichnis kopiert (In der Variable $zip_rohling stehe der Name der Buch-Rohlingsdatei samt Verzeichnis):

copy($zip_rohling, $zip_name);

Im nächsten Schritt wird für die ZIP-Funktionen von PHP das Archiv geöffnet:

$ziph = new ZipArchive();
$ziph->open($zip_name, ZIPARCHIVE::CHECKCONS);

Sofern nicht schon im Rohling vorhanden, können statisch vorhandene Dateien in das Archiv integriert werden. Stehe etwa in $datei der Pfad zu einer zu integrierenden Datei und in $zip_dateiname der gewünschte Pfad zur Datei im Archiv, so fügt man die Datei wie folgt zum Archiv hinzu:

$ziph->addFile($datei, $zip_dateiname);

Liegt die Datei hingegen etwa dynamisch erzeugt als Zeichenkette vor, ist ein anderer Aufruf zu verwenden, wobei man besonders auf die andere Reihenfolge der Parameter achten muß. Steht etwa die OPF-Datei in der Zeichenkette $opf, so verwendet man zum Beispiel folgenden Aufruf, um dies als 'Inhalt/index.opf' zum Archiv hinzuzufügen:

$ziph->addFromString('Inhalt/index.opf', $opf);

So werden nun sukzessive alle Dateien des Buches zum Buch hinzugefügt. Ist das Archiv beziehungsweise Buch fertig, wird das Archiv geschlossen:

$ziph->close();

Buch bereitstellen

Per Verweis

Nun kann dem Leser ein Verweis zum Buch angegeben werden, um dieses auf den eigenen Rechner zu laden. Dies kann direkt erfolgen oder aber auch über ein weiteres PHP-Skript. Dieses Skript kann dann das Buch auf dem Dienstrechner gleich wieder löschen. Wird dem Leser nur ein Verweis auf das Buch angegeben, so sollte ihm auch ein Verweis auf ein Skript angeboten werden, um das individuelle Buch selbst zu löschen. Ansonsten bietet es sich an, entweder ab und an manuell aufzuräumen oder aber andere, von Besuchern regelmäßig aufgerufene Skripte damit zu beauftragen, alte, noch nicht gelöschte Bücher wieder zu beseitigen.

Eine weitere Möglichkeit besteht darin, das Buch nach der Erstellung in eine Zeichenkette zu konvertieren und dann komplett mit dem Pseudoprotokoll 'data' in einen Verweis zu schreiben und das Buch sofort zu löschen. Der Leser kann dann das Buch aus dem Verweis heraus auf seinen Rechner laden. So ist jedenfalls gewährleistet, daß immer gleich aufgeräumt ist und das Buch nur exakt dem Leser verfügbar ist, der es auch angefordert hat, sofern man den Verweis nur diesem Leser anzeigt, das Buch also nicht abspeichert. Das Verfahren eignet sich nur bei Büchern, deren Größe noch gut in den Speicher des PHP-Programmes paßt.
Anlegen der Zeichenkette:

$archiv = file_get_contents($zip_name);
unlink($zip_name);
$archivb='data:application/epub+zip;base64,' . base64_encode($archiv);
$archiv='';

Der Verweis wird dann etwa wie folgt in der normalen Ausgabe erzeugt:

echo "<a href=\"$archivb\" target=\"_blank\">Buch-Rohling</a>";

Diese Möglichkeit wird beim hiesigen Generator verwendet.

Im Bedarfsfalle kann natürlich auch auf dem Dienstrechner eine Statistik angelegt werden oder jemanden eine email geschickt werden mit einer Nachricht, daß ein Buch erstellt wurde, falls es Bedarf gibt, die Anzahl der erzeugten Bücher zu beobachten oder auch Kontaktdaten der Leser abzulegen, sofern diese zuvor abgefragt wurden. Sofern dies geschieht, sind die Leser natürlich darauf hinzuweisen, wozu die Daten verwendet werden, sofern sie aufbewahrt werden.

Per Post

Hat der Leser eine email-Adresse angegeben oder auch eine Postadresse oder dergleichen, kann das Dienstprogramm natürlich auch verwendet werden, um das Buch dem Leser per email zukommen zu lassen - oder aber sich selbst, um es per klassischer Post oder einem ähnlichen Verfahren zu verschicken.
Auch hier sind die Leser natürlich darauf hinzuweisen, wozu die von ihnen angegebenen Daten verwendet werden, insbesondere sofern dies darüber hinausgeht, ihnen das jeweilige Buch zukommen zu lassen.

Bei einer Auslieferung per email kann es auch Größenbeschränkungen geben, eine gängige Beschränkung liegt etwa bei 5 MiB, was schon ein ordentliche Buchgröße ist, sofern es keine großen Bilder und vorrangig nur Text enthält. Die Beschränkung kann sowohl beim Dienstprogramm vorliegen, welches dann keine größeren emails verschicken mag, aber auch dem email-Dienstprogramm des Empfängers, welches ebenfalls die Annahme größerer emails verweigern kann. Welche Größe funktioniert, ist also nicht genau vom Autor der Skriptes zu prognostizieren, Bücher unterhalb von 5 MiB sollte aber kein Problem darstellen.

Bei größeren Büchern kann immer noch die URI des erzeugten Buches und eine URI zum Löschen auf dem Dienstrechner übermittelt werden, sofern man eine Verifizierung per email benötigt und die URIs nicht gleich direkt bereitstellen möchte.