Repairing a book¶
EpubFile::repair() fixes the problems validate() reports that have one safe, deterministic fix, and returns every change it made. It works on the loaded book, including unsaved edits; save() writes the result.
use PhpEpub\EpubFile;
$epubFile = EpubFile::open('/path/to/book.epub');
foreach ($epubFile->repair() as $fix) {
echo $fix, "\n"; // e.g. "MANIFEST_FILE_MISSING (EPUB/gone.xhtml): Removed the manifest item "gone", which has no file, from the manifest and the spine."
}
$epubFile->save('/path/to/repaired.epub');
public function repair(?RepairOptions $options = null): array
Returns a list of PhpEpub\Repair\AppliedFix objects with a code (the ValidationIssue code the change resolves), a description and a location (a file relative to the book root or a package value, or null). The list is empty when the book needed nothing. A second repair() changes nothing, and re-running validate() reports none of the fixed codes for that book.
A repair never deletes a file of the book. PhpEpub\Repair\Repairer is the class behind EpubFile::repair(); new Repairer($epubFile) does the same.
What is fixed¶
Fix (RepairFix) |
Codes | What it does |
|---|---|---|
ModifiedDate |
METADATA_MODIFIED_MISSING |
Sets dcterms:modified to the current time (UTC) |
Language |
METADATA_LANGUAGE_MISSING |
Sets dc:language to the default language (en) |
Identifier |
METADATA_IDENTIFIER_MISSING, METADATA_UNIQUE_IDENTIFIER |
Gives the package a unique identifier: a urn:uuid: when it has no value, else its first non-empty dc:identifier is made the unique one |
Navigation |
NAV_MISSING, NCX_MISSING, NAV_EMPTY, NCX_EMPTY |
Creates the navigation document (from the NCX, else the headings, else the reading order) or the NCX (from the headings, else the reading order); fills an empty table of contents from the headings, else the reading order |
TocLinks |
TOC_LINK_NOT_IN_MANIFEST |
Drops table-of-contents entries that link to a file that is not in the manifest; an entry with children stays as a heading |
MissingFiles |
MANIFEST_FILE_MISSING |
Removes a manifest item whose file is missing from the manifest and the spine |
SpineReferences |
SPINE_UNKNOWN_IDREF, SPINE_DUPLICATE_IDREF |
Removes spine references to unknown items, and repeated references (the first stays) |
UnlistedFiles |
FILE_NOT_IN_MANIFEST |
Adds the file to the manifest. An XHTML document is not added to the spine: the reading order is a decision for the author. Editor and system files (.DS_Store, Thumbs.db, desktop.ini, __MACOSX/, iTunesMetadata.plist, iTunesArtwork, any hidden file) are left alone |
MediaTypes |
MEDIA_TYPE_MISMATCH |
Corrects an image's media type from its content, and a type declared as XHTML for a file that is not XML from its extension; a file that cannot be decided stays reported, and a document of the reading order is never retyped as a non-content type |
DuplicateIds |
DUPLICATE_ID |
Gives a manifest item whose id an earlier item uses a new id (id-2). The first keeps the id, so the spine and other references keep pointing at it. Repeated ids outside the manifest are not fixed |
Cover |
COVER_NOT_IMAGE |
Removes the cover-image property from an item that is not an image; completes a half-declared cover (the EPUB 3 cover-image property and the EPUB 2 cover meta, including a cover named by the <guide>); declares an image (its content must be one) named cover.* or cover-image.* when the book declares none. Reported as COVER_NOT_FLAGGED and COVER_NOT_DECLARED |
ManifestProperties |
MANIFEST_PROPERTY_MISSING, MANIFEST_PROPERTY_UNNEEDED |
Recomputes the scripted, svg, remote-resources and mathml properties of the XHTML documents |
UpgradeToEpub3 |
(none) | Converts an EPUB 2 book with upgradeToEpub3(); reported as UPGRADED_TO_EPUB3. Off by default |
Fixes that address manifest items by id (MissingFiles, MediaTypes, Cover, ManifestProperties, UpgradeToEpub3) are skipped while the manifest repeats an id and DuplicateIds is not selected: they could change the wrong item.
Everything else validate() reports has no safe fix and stays (a missing title, XHTML that is not well-formed, content documents that refer to missing files, hrefs that point outside the book, unreadable navigation).
Choosing the fixes¶
use PhpEpub\Repair\RepairFix;
use PhpEpub\Repair\RepairOptions;
$options = (new RepairOptions())
->without(RepairFix::UnlistedFiles)
->with(RepairFix::UpgradeToEpub3)
->withDefaultLanguage('fr');
$fixes = $epubFile->repair($options);
// Only these:
$fixes = $epubFile->repair(RepairOptions::only(RepairFix::Language, RepairFix::ModifiedDate));
public function __construct(?array $fixes = null, string $defaultLanguage = 'en', ?DateTimeInterface $now = null)
public static function only(RepairFix ...$fixes): self
public function with(RepairFix ...$fixes): self
public function without(RepairFix ...$fixes): self
public function withDefaultLanguage(string $language): self
public function withNow(?DateTimeInterface $now): self
public function includes(RepairFix $fix): bool
$fixes defaults to every fix except UpgradeToEpub3 (RepairFix::defaults()). The default language must be a well-formed BCP 47 tag, else an Exception is thrown. $now is the time written as a missing dcterms:modified (the current time when null); pass a fixed time in tests.