class BookReaderMeta {
+ // Fields from _meta.xml to add to response (if present)
+ var $metaFields = array(
+ 'title' => 'title',
+ 'author' => 'author',
+ 'publisher' => 'publisher',
+ 'date' => 'date',
+ 'language' => 'language',
+ 'contributor' => 'contributor',
+ 'collection' => 'collection',
+ 'page-progression' => 'pageProgression',
+ );
+
+ var $metaDefaults = array(
+ 'pageProgression' => 'lr',
+ );
+
+ // Stash spot for callback data... where are closures when we need them?
+ static $cbData = NULL;
+
// Builds metadata object (to be encoded as JSON)
- function buildMetadata($id, $itemPath, $bookId, $server) {
+ function buildMetadata($id, $itemPath, $subPrefix, $server) {
$response = array();
- if (! $bookId) {
- $bookId = $id;
- }
- $subItemPath = $itemPath . '/' . $bookId;
-
if ("" == $id) {
$this->BRFatal("No identifier specified!");
}
$this->BRFatal("Bad id!");
}
- // XXX check here that subitem is okay
-
$filesDataFile = "$itemPath/${id}_files.xml";
if (file_exists($filesDataFile)) {
$this->BRfatal("File metadata not found!");
}
- $imageStackInfo = $this->findImageStack($bookId, $filesData);
+ $imageStackInfo = $this->findImageStack($subPrefix, $filesData);
if ($imageStackInfo['imageFormat'] == 'unknown') {
$this->BRfatal('Couldn\'t find image stack');
}
+ // Update subPrefix -> may have been autodetected
+ $subPrefix = $imageStackInfo['subPrefix'];
+ $subItemPath = $itemPath . '/' . $subPrefix;
+
$imageFormat = $imageStackInfo['imageFormat'];
$archiveFormat = $imageStackInfo['archiveFormat'];
$scanDataFile = "${subItemPath}_scandata.xml";
$scanDataZip = "$itemPath/scandata.zip";
if (file_exists($scanDataFile)) {
+ $this->checkPrivs($scanDataFile);
$scanData = simplexml_load_file($scanDataFile);
} else if (file_exists($scanDataZip)) {
+ $this->checkPrivs($scanDataZip);
$cmd = 'unzip -p ' . escapeshellarg($scanDataZip) . ' scandata.xml';
exec($cmd, $output, $retval);
if ($retval != 0) {
}
# Load some values from meta.xml
- $pageProgression = 'lr'; // default
- if ('' != $metaData->{'page-progression'}) {
- $pageProgression = $metaData->{"page-progression"};
+ foreach ($this->metaFields as $srcName => $destName) {
+ if ($metaData->{$srcName}) {
+ $response[$destName] = $metaData->{$srcName} . '';
+ } else {
+ if (array_key_exists($destName, $this->metaDefaults)) {
+ $response[$destName] = $this->metaDefaults[$destName];
+ }
+ }
}
// General metadata
- $response['title'] = $metaData->title . ''; // XXX renamed
- $response['numPages'] = count($pageNums); // XXX renamed
+ $response['numPages'] = count($pageNums); // $$$ renamed
if ('' != $titleLeaf) {
- $response['titleLeaf'] = $titleLeaf; // XXX change to titleIndex - do leaf mapping here
+ $response['titleLeaf'] = $titleLeaf; // $$$ change to titleIndex - do leaf mapping here
$titleIndex = $this->indexForLeaf($titleLeaf, $leafNums);
if ($titleIndex !== NULL) {
$response['titleIndex'] = intval($titleIndex);
}
}
$response['url'] = "http://www.archive.org/details/$id";
- $response['pageProgression'] = $pageProgression . '';
$response['pageWidths'] = $pageWidths;
$response['pageHeights'] = $pageHeights;
$response['pageNums'] = $pageNums;
// Internet Archive specific
- $response['itemId'] = $id; // XXX renamed
- $response['bookId'] = $bookId; // XXX renamed
+ $response['itemId'] = $id; // $$$ renamed
+ $response['subPrefix'] = $subPrefix; // $$$ renamed
$response['itemPath'] = $itemPath;
$response['zip'] = $imageStackFile;
$response['server'] = $server;
function BRFatal($string) {
// $$$ TODO log error
- echo "alert('$string');\n";
- die(-1);
+ throw new Exception("Metadata error: $string");
+ //echo "alert('$string');\n";
+ //die(-1);
}
// Returns true if a page should be added based on it's information in
// Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
function findImageStack($subPrefix, $filesData) {
-
- // $$$ The order of the image formats determines which will be returned first
+
+ // The order of the image formats determines which will be returned first
$imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
+ $imageFormatOrder = array_values($imageFormats);
$archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
$imageGroup = implode('|', array_keys($imageFormats));
$archiveGroup = implode('|', array_keys($archiveFormats));
// $$$ Currently only return processed images
$imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
-
- foreach ($filesData->file as $file) {
- if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
- if (preg_match($imageStackRegex, $file->format, $matches)) {
+
+ // Strategy:
+ // - Find potential image stacks, regardless of subPrefix
+ // - If not given subPrefix sort based on potential subPrefix and assign based on asciibetical first
+ // - Filter results by subPrefix
+ // - Sort based on image format
+ // - Take best match
+
+ $imageStacks = array();
+ foreach ($filesData->file as $file) {
+ if ( preg_match($imageStackRegex, $file->format, $matches) === 1 ) {
+ $imageFormat = $imageFormats[$matches[2]];
+ $archiveFormat = $archiveFormats[$matches[3]];
+ $imageStackFile = $file['name'] . '';
- // Make sure we have a regular image stack
- $imageFormat = $imageFormats[$matches[2]];
- if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {
- return array('imageFormat' => $imageFormat,
- 'archiveFormat' => $archiveFormats[$matches[3]],
- 'imageStackFile' => $file['name']);
- }
+ if ( preg_match("#(.*)_${imageFormat}\.${archiveFormat}#", $imageStackFile, $matches) === 0) {
+ // stack filename not regular
+ continue;
+ } else {
+ array_push($imageStacks, array(
+ 'imageFormat' => $imageFormat,
+ 'archiveFormat' => $archiveFormat,
+ 'imageStackFile' => $imageStackFile,
+ 'subPrefix' => $matches[1])
+ );
}
+
+ }
+ }
+
+ // print("<pre>");
+ // print("found subPrefix $subPrefix\n");
+ // print_r($imageStacks);
+ // die(0);
+
+ function subPrefixSort($imageStackA, $imageStackB) {
+ return strcmp($imageStackA['subPrefix'], $imageStackB['subPrefix']);
+ }
+ if (! $subPrefix) {
+ usort($imageStacks, 'subPrefixSort');
+ $subPrefix = $imageStacks[0]['subPrefix'];
+ }
+
+ self::$cbData = $subPrefix;
+ function subPrefixFilter($imageStack) {
+ return $imageStack['subPrefix'] == BookReaderMeta::$cbData;
+ }
+ $imageStacks = array_filter($imageStacks, 'subPrefixFilter');
+
+ function formatSort($imageStackA, $imageStackB) {
+ $formatA = $imageStackA['imageFormat'];
+ $formatB = $imageStackB['imageFormat'];
+ if ($formatA == $formatB) {
+ return 0;
+ }
+
+ $indexA = array_search($formatA, $imageFormatOrder);
+ $indexB = array_search($formatB, $imageFormatOrder);
+ // We already matched base on format, so both indices should be set
+ if ($indexA == $indexB) {
+ return 0;
}
+ return ($indexA < $indexB) ? 1 : -1;
}
+ usort($imageStacks, 'formatSort'); // necessary to remap keys
- return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
+ if ( count($imageStacks) > 0 ) {
+ return $imageStacks[0];
+ } else {
+ return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
+ }
}
function isValidCallback($identifier) {
return $leafNums[$index]; // $$$ todo change to instance variables
}
- function imageURL($leafNum, $metadata, $scale, $rotate) {
+ function imageURL($leafNum, $metadata, $scale = null, $rotate = null) {
// "Under the hood", non-public, dynamically changing (achtung!) image URLs currently look like:
// http://{server}/BookReader/BookReaderImages.php?zip={zipPath}&file={filePath}&scale={scale}&rotate={rotate}
// e.g. http://ia311213.us.archive.org/BookReader/BookReaderImages.php?zip=/0/items/coloritsapplicat00andriala/coloritsapplicat00andriala_jp2.zip&file=coloritsapplicat00andriala_jp2/coloritsapplicat00andriala_0009.jp2&scale=8&rotate=0
- $filePath = $this->imageFilePath($leafNum, $metadata['bookId'], $metadata['imageFormat']);
+ $filePath = $this->imageFilePath($leafNum, $metadata['subPrefix'], $metadata['imageFormat']);
$url = 'http://' . $metadata['server'] . '/BookReader/BookReaderImages.php?zip=' . $metadata['zip'] . '&file=' . $filePath;
- if (defined($scale)) {
+ if ($scale !== null) {
$url .= '&scale=' . $scale;
}
- if (defined($rotate)) {
+ if ($rotate !== null) {
$url .= '&rotate=' . $rotate;
}
function previewURL($page, $metadata) {
$query = array(
'id' => $metadata['itemId'],
- 'bookId' => $metadata['bookId'],
+ 'subPrefix' => $metadata['subPrefix'],
'itemPath' => $metadata['itemPath'],
'server' => $metadata['server'],
'page' => $page,
return 'http://' . $metadata['server'] . '/BookReader/BookReaderPreview.php?' . http_build_query($query, '', '&');
}
- function imageFilePath($leafNum, $bookId, $format) {
- return sprintf("%s_%s/%s_%04d.%s", $bookId, $format, $bookId, intval($leafNum), $format);
+ function imageFilePath($leafNum, $subPrefix, $format) {
+ $pathParts = pathinfo($subPrefix);
+ $almostIdentifier = $pathParts['basename'];
+ return sprintf("%s_%s/%s_%04d.%s", $almostIdentifier, $format, $almostIdentifier, intval($leafNum), $format);
+ }
+
+ // Parse date from _meta.xml to integer
+ function parseYear($dateFromMetaXML) {
+ // grab the first run of digits
+ if (preg_match('|(\d+)|', $dateFromMetaXML, $matches)) {
+ return (int)$matches[1];
+ }
+ return null;
}
function processRequest($requestEnv) {
- $id = $requestEnv['itemId']; // XXX renamed
+ $id = $requestEnv['itemId']; // $$$ renamed
$itemPath = $requestEnv['itemPath'];
- $bookId = $requestEnv['bookId']; // XXX renamed
+ $subPrefix = $requestEnv['subPrefix']; // $$$ renamed
$server = $requestEnv['server'];
// Check if we're on a dev vhost and point to JSIA in the user's public_html on the datanode
// $$$ TODO consolidate this logic
- if (strpos($_SERVER["REQUEST_URI"], "/~mang") === 0) { // Serving out of home dir
- $server .= ':80/~mang';
- } else if (strpos($_SERVER["REQUEST_URI"], "/~testflip") === 0) { // Serving out of home dir
- $server .= ':80/~testflip';
+ $devHosts = array('testflip', 'rkumar', 'mang');
+ foreach ($devHosts as $host) {
+ if (strpos($_SERVER["REQUEST_URI"], '/~' . $host) === 0) { // Serving out of home dir
+ $server .= ':80/' . $host;
+ }
}
- $this->emitResponse( $this->buildMetadata($id, $itemPath, $bookId, $server) );
+ $this->emitResponse( $this->buildMetadata($id, $itemPath, $subPrefix, $server) );
}
+
+ function checkPrivs($filename) {
+ if (!is_readable($filename)) {
+ header('HTTP/1.1 403 Forbidden');
+ exit(0);
+ }
+ }
+
}
?>