Merge pull request #93 from Marsender/master
Création de bases Calibre pour COPS
This commit is contained in:
commit
2bcd38f4f1
6
base.php
6
base.php
|
@ -157,12 +157,12 @@ function localize($phrase, $count=-1) {
|
|||
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
|
||||
}
|
||||
$lang_file_en = NULL;
|
||||
$lang_file = 'lang/Localization_' . $lang . '.json';
|
||||
$lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
|
||||
if (!file_exists($lang_file)) {
|
||||
$lang_file = 'lang/' . 'Localization_en.json';
|
||||
$lang_file = dirname(__FILE__). '/lang/' . 'Localization_en.json';
|
||||
}
|
||||
elseif ($lang != "en") {
|
||||
$lang_file_en = 'lang/' . 'Localization_en.json';
|
||||
$lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
|
||||
}
|
||||
$lang_file_content = file_get_contents($lang_file);
|
||||
/* Load the language file as a JSON object and transform it into an associative array */
|
||||
|
|
209
resources/epub-loader/BaseExport.class.php
Normal file
209
resources/epub-loader/BaseExport.class.php
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
/**
|
||||
* BaseExport class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
class BaseExport
|
||||
{
|
||||
protected $mProperties = null;
|
||||
protected $mFileName = '';
|
||||
protected $mSearch = null;
|
||||
protected $mReplace = null;
|
||||
|
||||
public $mFormatProperty = true;
|
||||
|
||||
/**
|
||||
* Open an export file (or create if file does not exist)
|
||||
*
|
||||
* @param string Export file name
|
||||
* @param boolean Force file creation
|
||||
*/
|
||||
public function __construct($inFileName, $inCreate = false)
|
||||
{
|
||||
if ($inCreate && file_exists($inFileName)) {
|
||||
if (!unlink($inFileName)) {
|
||||
$error = sprintf('Cannot remove file: %s', $inFileName);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
$this->mFileName = $inFileName;
|
||||
|
||||
$this->mProperties = array();
|
||||
}
|
||||
|
||||
public function ClearProperties()
|
||||
{
|
||||
$this->mProperties = array();
|
||||
}
|
||||
|
||||
public function SetProperty($inKey, $inValue)
|
||||
{
|
||||
// Don't store empty keys
|
||||
if (empty($inKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->mFormatProperty) {
|
||||
$inValue = $this->FormatProperty($inValue);
|
||||
}
|
||||
|
||||
$this->mProperties[$inKey] = $inValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a property
|
||||
*
|
||||
* @param string or array of strings to format
|
||||
* @return string or array of strings formated
|
||||
*/
|
||||
protected function FormatProperty($inValue)
|
||||
{
|
||||
if (!isset($inValue)) {
|
||||
return '';
|
||||
}
|
||||
if (is_numeric($inValue)) {
|
||||
return (string)$inValue;
|
||||
}
|
||||
if (is_array($inValue)) {
|
||||
// Recursive call for arrays
|
||||
foreach ($inValue as $key => $value) {
|
||||
$inValue[$key] = $this->FormatProperty($value);
|
||||
}
|
||||
return $inValue;
|
||||
}
|
||||
if (!is_string($inValue) || empty($inValue)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Replace html entities with normal characters
|
||||
$str = html_entity_decode($inValue, ENT_COMPAT, 'UTF-8');
|
||||
// Replace characters
|
||||
if (isset($this->mSearch)) {
|
||||
$str = str_replace($this->mSearch, $this->mReplace, $str);
|
||||
}
|
||||
|
||||
// Strip double spaces
|
||||
while (strpos($str, ' ') !== false) {
|
||||
$str = str_replace(' ', ' ', $str);
|
||||
}
|
||||
|
||||
// Trim
|
||||
$str = trim($str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to file
|
||||
*
|
||||
* @throws Exception if error
|
||||
*/
|
||||
public function SaveToFile()
|
||||
{
|
||||
// Write the file
|
||||
$content = $this->GetContent();
|
||||
if (!file_put_contents($this->mFileName, $content)) {
|
||||
$error = sprintf('Cannot save export to file: %s', $this->mFileName);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send download http headers
|
||||
*
|
||||
* @param string $inFileName Download file name to display in the browser
|
||||
* @param int $inFileSize Download file size
|
||||
* @param string $inCodeSet Charset
|
||||
* @throws exception if http headers have been already sent
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function SendDownloadHeaders($inFileName, $inFileSize = null, $inCodeSet = 'utf-8')
|
||||
{
|
||||
// Throws excemtion if http headers have been already sent
|
||||
$filename = '';
|
||||
$linenum = 0;
|
||||
if (headers_sent($filename, $linenum)) {
|
||||
$error = sprintf('Http headers already sent by file: %s ligne %d', $filename, $linenum);
|
||||
throw new Exception($error);
|
||||
}
|
||||
|
||||
$inFileName = str_replace(' ', '', basename($inFileName)); // Cleanup file name
|
||||
$ext = strtolower(substr(strrchr($inFileName, '.'), 1));
|
||||
|
||||
switch ($ext) {
|
||||
case 'pdf':
|
||||
$contentType = 'application/pdf';
|
||||
break;
|
||||
case 'zip':
|
||||
$contentType = 'application/zip';
|
||||
break;
|
||||
case 'xml':
|
||||
$contentType = 'text/xml';
|
||||
if (!empty($inCodeSet)) {
|
||||
$contentType .= '; charset=' . $inCodeSet . '"';
|
||||
}
|
||||
break;
|
||||
case 'txt':
|
||||
$contentType = 'text/plain';
|
||||
if (!empty($inCodeSet)) {
|
||||
$contentType .= '; charset=' . $inCodeSet . '"';
|
||||
}
|
||||
break;
|
||||
case 'csv':
|
||||
$contentType = 'text/csv';
|
||||
if (!empty($inCodeSet)) {
|
||||
$contentType .= '; charset=' . $inCodeSet . '"';
|
||||
}
|
||||
break;
|
||||
case 'html':
|
||||
$contentType = 'text/html';
|
||||
if (!empty($inCodeSet)) {
|
||||
$contentType .= '; charset=' . $inCodeSet . '"';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$contentType = 'application/force-download';
|
||||
break;
|
||||
}
|
||||
|
||||
// Send http headers for download
|
||||
header('Content-disposition: attachment; filename="' . $inFileName . '"');
|
||||
Header('Content-Type: ' . $contentType);
|
||||
//header('Content-Transfer-Encoding: binary');
|
||||
if (isset($inFileSize)) {
|
||||
header('Content-Length: ' . $inFileSize);
|
||||
}
|
||||
|
||||
// Send http headers to remove the browser cache
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate("D, d M Y H:i:s") . ' GMT');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* Download export and stop further script execution
|
||||
*/
|
||||
public function Download()
|
||||
{
|
||||
$content = $this->GetContent();
|
||||
|
||||
// Send http download headers
|
||||
$size = strlen($content);
|
||||
$this->SendDownloadHeaders($this->mFileName, $size);
|
||||
|
||||
// Send file content to download
|
||||
echo $content;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
126
resources/epub-loader/BookExport.class.php
Normal file
126
resources/epub-loader/BookExport.class.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/**
|
||||
* BookExport class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
require_once(realpath(dirname(__FILE__)) . '/CsvExport.class.php');
|
||||
|
||||
class BookExport
|
||||
{
|
||||
private $mExport = null;
|
||||
private $mNbBook = 0;
|
||||
|
||||
const eExportTypeCsv = 1;
|
||||
const CsvSeparator = "\t";
|
||||
|
||||
/**
|
||||
* Open an export file (or create if file does not exist)
|
||||
*
|
||||
* @param string Export file name
|
||||
* @param enum Export type
|
||||
* @param boolean Force file creation
|
||||
* @throws Exception if error
|
||||
*/
|
||||
public function __construct($inFileName, $inExportType, $inCreate = false)
|
||||
{
|
||||
switch ($inExportType) {
|
||||
case self::eExportTypeCsv:
|
||||
$this->mExport = new CsvExport($inFileName);
|
||||
break;
|
||||
default:
|
||||
$error = sprintf('Incorrect export type: %d', $inExportType);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an epub to the export
|
||||
*
|
||||
* @param string Epub file name
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function AddEpub($inFileName)
|
||||
{
|
||||
// Load the book infos
|
||||
$bookInfos = new BookInfos();
|
||||
$bookInfos->LoadFromEpub($inFileName);
|
||||
// Add the book
|
||||
$this->AddBook($bookInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new book to the export
|
||||
*
|
||||
* @param object BookInfo object
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function AddBook($inBookInfo)
|
||||
{
|
||||
// Add export header
|
||||
if ($this->mNbBook++ == 0) {
|
||||
$i = 1;
|
||||
$this->mExport->SetProperty($i++, 'Format');
|
||||
$this->mExport->SetProperty($i++, 'Path');
|
||||
$this->mExport->SetProperty($i++, 'Name');
|
||||
$this->mExport->SetProperty($i++, 'Uuid');
|
||||
$this->mExport->SetProperty($i++, 'Uri');
|
||||
$this->mExport->SetProperty($i++, 'Title');
|
||||
$this->mExport->SetProperty($i++, 'Authors');
|
||||
$this->mExport->SetProperty($i++, 'AuthorsSort');
|
||||
$this->mExport->SetProperty($i++, 'Language');
|
||||
$this->mExport->SetProperty($i++, 'Description');
|
||||
$this->mExport->SetProperty($i++, 'Subjects');
|
||||
$this->mExport->SetProperty($i++, 'Cover');
|
||||
$this->mExport->SetProperty($i++, 'Isbn');
|
||||
$this->mExport->SetProperty($i++, 'Rights');
|
||||
$this->mExport->SetProperty($i++, 'Publisher');
|
||||
$this->mExport->AddContent();
|
||||
}
|
||||
|
||||
// Add book infos to the export
|
||||
$i = 1;
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mFormat);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mPath);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mName);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mUuid);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mUri);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mTitle);
|
||||
$this->mExport->SetProperty($i++, implode(' - ', $inBookInfo->mAuthors));
|
||||
$this->mExport->SetProperty($i++, implode(' - ', array_keys($inBookInfo->mAuthors)));
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mLanguage);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mDescription);
|
||||
$this->mExport->SetProperty($i++, implode(' - ', $inBookInfo->mSubjects));
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mCover);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mIsbn);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mRights);
|
||||
$this->mExport->SetProperty($i++, $inBookInfo->mPublisher);
|
||||
|
||||
$this->mExport->AddContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Download export and stop further script execution
|
||||
*/
|
||||
public function Download()
|
||||
{
|
||||
$this->mExport->Download();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save export to file
|
||||
*/
|
||||
public function SaveToFile()
|
||||
{
|
||||
$this->mExport->SaveToFile();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
65
resources/epub-loader/BookInfos.class.php
Normal file
65
resources/epub-loader/BookInfos.class.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* BookInfos class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
require_once(realpath(dirname(__FILE__)) . '/ZipFile.class.php');
|
||||
require_once(realpath(dirname(dirname(__FILE__))) . '/php-epub-meta/epub.php');
|
||||
|
||||
/**
|
||||
* BookInfos class contains informations about a book,
|
||||
* and methods to load this informations from multiple sources (eg epub file)
|
||||
*/
|
||||
class BookInfos
|
||||
{
|
||||
public $mPath = '';
|
||||
public $mName = '';
|
||||
public $mFormat = '';
|
||||
public $mUuid = '';
|
||||
public $mUri = '';
|
||||
public $mTitle = '';
|
||||
public $mAuthors = null;
|
||||
public $mLanguage = '';
|
||||
public $mDescription = '';
|
||||
public $mSubjects = null;
|
||||
public $mCover = '';
|
||||
public $mIsbn = '';
|
||||
public $mRights = '';
|
||||
public $mPublisher = '';
|
||||
|
||||
/**
|
||||
* Loads book infos from an epub file
|
||||
*
|
||||
* @param string Epub full file name
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function LoadFromEpub($inFileName)
|
||||
{
|
||||
// Load the epub file
|
||||
$epub = new EPub($inFileName, 'ZipFile');
|
||||
|
||||
// Get the epub infos
|
||||
$this->mFormat = 'epub';
|
||||
$this->mPath = pathinfo($inFileName, PATHINFO_DIRNAME);
|
||||
$this->mName = pathinfo($inFileName, PATHINFO_FILENAME);
|
||||
$this->mUuid = $epub->Uuid();
|
||||
$this->mUri = $epub->Uri();
|
||||
$this->mTitle = $epub->Title();
|
||||
$this->mAuthors = $epub->Authors();
|
||||
$this->mLanguage = $epub->Language();
|
||||
$this->mDescription = $epub->Description();
|
||||
$this->mSubjects = $epub->Subjects();
|
||||
$this->mCover = $epub->getCoverItem();
|
||||
$this->mIsbn = $epub->ISBN();
|
||||
$this->mRights = $epub->Copyright();
|
||||
$this->mPublisher = $epub->Publisher();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
254
resources/epub-loader/CalibreDbLoader.class.php
Normal file
254
resources/epub-loader/CalibreDbLoader.class.php
Normal file
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/**
|
||||
* CalibreDbLoader class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
require_once(realpath(dirname(__FILE__)) . '/BookInfos.class.php');
|
||||
|
||||
/**
|
||||
* Calibre database sql file that comes unmodified from Calibre project:
|
||||
* /calibre/resources/metadata_sqlite.sql
|
||||
*/
|
||||
define('CalibreCreateDbSql', realpath(dirname(__FILE__)) . '/metadata_sqlite.sql');
|
||||
|
||||
/**
|
||||
* CalibreDbLoader class allows to open or create a new Calibre database,
|
||||
* and then add BookInfos objects into the database
|
||||
*/
|
||||
class CalibreDbLoader
|
||||
{
|
||||
private $mDb = null;
|
||||
|
||||
/**
|
||||
* Open a Calibre database (or create if database does not exist)
|
||||
*
|
||||
* @param string Calibre database file name
|
||||
* @param boolean Force database creation
|
||||
*/
|
||||
public function __construct($inDbFileName, $inCreate = false)
|
||||
{
|
||||
if ($inCreate || !file_exists($inDbFileName)) {
|
||||
$this->CreateDatabase($inDbFileName);
|
||||
}
|
||||
else {
|
||||
$this->OpenDatabase($inDbFileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an sqlite database
|
||||
*
|
||||
* @param string Database file name
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function CreateDatabase($inDbFileName)
|
||||
{
|
||||
// Read the sql file
|
||||
$content = file_get_contents(CalibreCreateDbSql);
|
||||
if ($content === false) {
|
||||
$error = sprintf('Cannot read sql file: %s', $inDbFileName);
|
||||
throw new Exception($error);
|
||||
}
|
||||
|
||||
// Remove the database file
|
||||
if (file_exists($inDbFileName) && !unlink($inDbFileName)) {
|
||||
$error = sprintf('Cannot remove database file: %s', $inDbFileName);
|
||||
throw new Exception($error);
|
||||
}
|
||||
|
||||
// Create the new database file
|
||||
$this->OpenDatabase($inDbFileName);
|
||||
|
||||
// Create the database tables
|
||||
try {
|
||||
$sqlArray = explode('CREATE ', $content);
|
||||
foreach ($sqlArray as $sql) {
|
||||
$sql = trim($sql);
|
||||
if (empty($sql)) {
|
||||
continue;
|
||||
}
|
||||
$sql = 'CREATE ' . $sql;
|
||||
$str = strtolower($sql);
|
||||
if (strpos($str, 'create view') !== false) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($str, 'title_sort') !== false) {
|
||||
continue;
|
||||
}
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$error = sprintf('Cannot create database: %s', $e->getMessage());
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an sqlite database
|
||||
*
|
||||
* @param string Database file name
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function OpenDatabase($inDbFileName)
|
||||
{
|
||||
try {
|
||||
// Init the Data Source Name
|
||||
$dsn = 'sqlite:' . $inDbFileName;
|
||||
// Open the database
|
||||
$this->mDb = new PDO($dsn); // Send an exception if error
|
||||
$this->mDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
//echo sprintf('Init database ok for: %s%s', $dsn, '<br />');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$error = sprintf('Cannot open database [%s]: %s', $dsn, $e->getMessage());
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an epub to the db
|
||||
*
|
||||
* @param string Epub file name
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function AddEpub($inFileName)
|
||||
{
|
||||
// Load the book infos
|
||||
$bookInfos = new BookInfos();
|
||||
$bookInfos->LoadFromEpub($inFileName);
|
||||
// Add the book
|
||||
$this->AddBook($bookInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new book into the db
|
||||
*
|
||||
* @param object BookInfo object
|
||||
* @throws Exception if error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function AddBook($inBookInfo)
|
||||
{
|
||||
$sql = 'insert into books(title, sort, uuid, path) values(:title, :sort, :uuid, :path)';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':title', $inBookInfo->mTitle);
|
||||
$stmt->bindParam(':sort', $inBookInfo->mTitle);
|
||||
$stmt->bindParam(':uuid', $inBookInfo->mUuid);
|
||||
$stmt->bindParam(':path', $inBookInfo->mPath);
|
||||
$stmt->execute();
|
||||
// Get the book id
|
||||
$sql = 'select id, title from books where uuid=:uuid';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':uuid', $inBookInfo->mUuid);
|
||||
$stmt->execute();
|
||||
$idBook = null;
|
||||
while ($post = $stmt->fetchObject()) {
|
||||
if (!isset($idBook)) {
|
||||
$idBook = $post->id;
|
||||
}
|
||||
else {
|
||||
$error = sprintf('Multiple book id for uuid: %s (already in title "%s")', $inBookInfo->mUuid, $post->title);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
if (!isset($idBook)) {
|
||||
$error = sprintf('Cannot find book id for uuid: %s', $inBookInfo->mUuid);
|
||||
throw new Exception($error);
|
||||
}
|
||||
// Add the book formats
|
||||
$sql = 'insert into data(book, format, name, uncompressed_size) values(:idBook, :format, :name, 0)';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':idBook', $idBook, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':format', $inBookInfo->mFormat);
|
||||
$stmt->bindParam(':name', $inBookInfo->mName);
|
||||
$stmt->execute();
|
||||
// Add the book identifiers
|
||||
if (!empty($inBookInfo->mUri)) {
|
||||
$sql = 'insert into identifiers(book, type, val) values(:idBook, :type, :value)';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$type = 'URI';
|
||||
$stmt->bindParam(':idBook', $idBook, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':type', $type);
|
||||
$stmt->bindParam(':value', $inBookInfo->mUri);
|
||||
$stmt->execute();
|
||||
}
|
||||
// Add the authors in the db
|
||||
foreach ($inBookInfo->mAuthors as $authorSort => $author) {
|
||||
// Get the author id
|
||||
$sql = 'select id from authors where name=:author';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':author', $author);
|
||||
$stmt->execute();
|
||||
$post = $stmt->fetchObject();
|
||||
if ($post) {
|
||||
$idAuthor = $post->id;
|
||||
}
|
||||
else {
|
||||
// Add a new author
|
||||
$sql = 'insert into authors(name, sort) values(:author, :sort)';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':author', $author);
|
||||
$stmt->bindParam(':sort', $authorSort);
|
||||
$stmt->execute();
|
||||
// Get the author id
|
||||
$sql = 'select id from authors where name=:author';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':author', $author);
|
||||
$stmt->execute();
|
||||
$idAuthor = null;
|
||||
while ($post = $stmt->fetchObject()) {
|
||||
if (!isset($idAuthor)) {
|
||||
$idAuthor = $post->id;
|
||||
}
|
||||
else {
|
||||
$error = sprintf('Multiple authors for name: %s', $author);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
||||
if (!isset($idAuthor)) {
|
||||
$error = sprintf('Cannot find author id for name: %s', $author);
|
||||
throw new Exception($error);
|
||||
}
|
||||
// Add the book author link
|
||||
$sql = 'insert into books_authors_link(book, author) values(:idBook, :idAuthor)';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->bindParam(':idBook', $idBook, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':idAuthor', $idAuthor, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check database for debug
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function CheckDatabase()
|
||||
{
|
||||
// Retrieve some infos for check only
|
||||
$sql = 'select id, title, sort from books';
|
||||
$stmt = $this->mDb->prepare($sql);
|
||||
$stmt->execute();
|
||||
while ($post = $stmt->fetchObject()) {
|
||||
$id = $post->id;
|
||||
$title = $post->title;
|
||||
$sort = $post->sort;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
77
resources/epub-loader/CsvExport.class.php
Normal file
77
resources/epub-loader/CsvExport.class.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* CsvExport class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
require_once(realpath(dirname(__FILE__)) . '/BaseExport.class.php');
|
||||
|
||||
class CsvExport extends BaseExport
|
||||
{
|
||||
private $mLines = null;
|
||||
|
||||
const CsvSeparator = "\t";
|
||||
|
||||
/**
|
||||
* Open an export file (or create if file does not exist)
|
||||
*
|
||||
* @param string Export file name
|
||||
* @param boolean Force file creation
|
||||
*/
|
||||
public function __construct($inFileName)
|
||||
{
|
||||
$this->mSearch = array("\r", "\n", self::CsvSeparator);
|
||||
$this->mReplace = array('', '<br />', '');
|
||||
|
||||
// Init container
|
||||
$this->mLines = array();
|
||||
|
||||
parent::__construct($inFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the current properties into the export content
|
||||
* and reset the properties
|
||||
*/
|
||||
public function AddContent()
|
||||
{
|
||||
$text = '';
|
||||
foreach ($this->mProperties as $key => $value) {
|
||||
$info = '';
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $value1) {
|
||||
// Escape quotes
|
||||
if (strpos($value1, '\'') !== false) {
|
||||
$value1 = '\'' . str_replace('\'', '\'\'', $value1) . '\'';
|
||||
}
|
||||
$text .= $value1 . self::CsvSeparator;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// Escape quotes
|
||||
if (strpos($value, '\'') !== false) {
|
||||
$value = '\'' . str_replace('\'', '\'\'', $value) . '\'';
|
||||
}
|
||||
$info = $value;
|
||||
}
|
||||
$text .= $info . self::CsvSeparator;
|
||||
}
|
||||
|
||||
$this->mLines[] = $text;
|
||||
|
||||
$this->ClearProperties();
|
||||
}
|
||||
|
||||
protected function GetContent()
|
||||
{
|
||||
$text = implode("\n", $this->mLines) . "\n";
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
119
resources/epub-loader/ZipFile.class.php
Normal file
119
resources/epub-loader/ZipFile.class.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
/**
|
||||
* ZipFile class
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author Didier Corbière <didier.corbiere@opale-concept.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* ZipFile class allows to open files inside a zip file with the standard php zip functions
|
||||
*/
|
||||
class ZipFile
|
||||
{
|
||||
private $mZip;
|
||||
private $mEntries;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mZip = null;
|
||||
$this->mEntries = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->Close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a zip file and read it's entries
|
||||
*
|
||||
* @param string $inFileName
|
||||
* @return boolean True if zip file has been correctly opended, else false
|
||||
*/
|
||||
public function Open($inFileName)
|
||||
{
|
||||
$this->Close();
|
||||
|
||||
$this->mZip = zip_open($inFileName);
|
||||
if (!$this->mZip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mEntries = array();
|
||||
|
||||
while ($entry = zip_read($this->mZip)) {
|
||||
$fileName = zip_entry_name($entry);
|
||||
$this->mEntries[$fileName] = $entry;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file exist in the zip entries
|
||||
*
|
||||
* @param string $inFileName File to search
|
||||
*
|
||||
* @return boolean True if the file exist, else false
|
||||
*/
|
||||
public function FileExists($inFileName)
|
||||
{
|
||||
if (!isset($this->mZip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->mEntries[$inFileName])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content of a file in the zip entries
|
||||
*
|
||||
* @param string $inFileName File to search
|
||||
*
|
||||
* @return mixed File content the file exist, else false
|
||||
*/
|
||||
public function FileRead($inFileName)
|
||||
{
|
||||
if (!isset($this->mZip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->mEntries[$inFileName])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$entry = $this->mEntries[$inFileName];
|
||||
if (!zip_entry_open($this->mZip, $entry)) {
|
||||
return false;
|
||||
}
|
||||
$data = zip_entry_read($entry, zip_entry_filesize($entry));
|
||||
zip_entry_close($entry);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the zip file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function Close()
|
||||
{
|
||||
if (!isset($this->mZip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
zip_close($this->mZip);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
549
resources/epub-loader/metadata_sqlite.sql
Normal file
549
resources/epub-loader/metadata_sqlite.sql
Normal file
|
@ -0,0 +1,549 @@
|
|||
CREATE TABLE authors ( id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
sort TEXT COLLATE NOCASE,
|
||||
link TEXT NOT NULL DEFAULT "",
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE books ( id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL DEFAULT 'Unknown' COLLATE NOCASE,
|
||||
sort TEXT COLLATE NOCASE,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
pubdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
series_index REAL NOT NULL DEFAULT 1.0,
|
||||
author_sort TEXT COLLATE NOCASE,
|
||||
isbn TEXT DEFAULT "" COLLATE NOCASE,
|
||||
lccn TEXT DEFAULT "" COLLATE NOCASE,
|
||||
path TEXT NOT NULL DEFAULT "",
|
||||
flags INTEGER NOT NULL DEFAULT 1,
|
||||
uuid TEXT,
|
||||
has_cover BOOL DEFAULT 0,
|
||||
last_modified TIMESTAMP NOT NULL DEFAULT "2000-01-01 00:00:00+00:00");
|
||||
CREATE TABLE books_authors_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
author INTEGER NOT NULL,
|
||||
UNIQUE(book, author)
|
||||
);
|
||||
CREATE TABLE books_languages_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
lang_code INTEGER NOT NULL,
|
||||
item_order INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE(book, lang_code)
|
||||
);
|
||||
CREATE TABLE books_plugin_data(id INTEGER PRIMARY KEY,
|
||||
book INTEGER NON NULL,
|
||||
name TEXT NON NULL,
|
||||
val TEXT NON NULL,
|
||||
UNIQUE(book,name));
|
||||
CREATE TABLE books_publishers_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
publisher INTEGER NOT NULL,
|
||||
UNIQUE(book)
|
||||
);
|
||||
CREATE TABLE books_ratings_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
rating INTEGER NOT NULL,
|
||||
UNIQUE(book, rating)
|
||||
);
|
||||
CREATE TABLE books_series_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
series INTEGER NOT NULL,
|
||||
UNIQUE(book)
|
||||
);
|
||||
CREATE TABLE books_tags_link ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
tag INTEGER NOT NULL,
|
||||
UNIQUE(book, tag)
|
||||
);
|
||||
CREATE TABLE comments ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NON NULL,
|
||||
text TEXT NON NULL COLLATE NOCASE,
|
||||
UNIQUE(book)
|
||||
);
|
||||
CREATE TABLE conversion_options ( id INTEGER PRIMARY KEY,
|
||||
format TEXT NOT NULL COLLATE NOCASE,
|
||||
book INTEGER,
|
||||
data BLOB NOT NULL,
|
||||
UNIQUE(format,book)
|
||||
);
|
||||
CREATE TABLE custom_columns (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
label TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
datatype TEXT NOT NULL,
|
||||
mark_for_delete BOOL DEFAULT 0 NOT NULL,
|
||||
editable BOOL DEFAULT 1 NOT NULL,
|
||||
display TEXT DEFAULT "{}" NOT NULL,
|
||||
is_multiple BOOL DEFAULT 0 NOT NULL,
|
||||
normalized BOOL NOT NULL,
|
||||
UNIQUE(label)
|
||||
);
|
||||
CREATE TABLE data ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NON NULL,
|
||||
format TEXT NON NULL COLLATE NOCASE,
|
||||
uncompressed_size INTEGER NON NULL,
|
||||
name TEXT NON NULL,
|
||||
UNIQUE(book, format)
|
||||
);
|
||||
CREATE TABLE feeds ( id INTEGER PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
script TEXT NOT NULL,
|
||||
UNIQUE(title)
|
||||
);
|
||||
CREATE TABLE identifiers ( id INTEGER PRIMARY KEY,
|
||||
book INTEGER NON NULL,
|
||||
type TEXT NON NULL DEFAULT "isbn" COLLATE NOCASE,
|
||||
val TEXT NON NULL COLLATE NOCASE,
|
||||
UNIQUE(book, type)
|
||||
);
|
||||
CREATE TABLE languages ( id INTEGER PRIMARY KEY,
|
||||
lang_code TEXT NON NULL COLLATE NOCASE,
|
||||
UNIQUE(lang_code)
|
||||
);
|
||||
CREATE TABLE library_id ( id INTEGER PRIMARY KEY,
|
||||
uuid TEXT NOT NULL,
|
||||
UNIQUE(uuid)
|
||||
);
|
||||
CREATE TABLE metadata_dirtied(id INTEGER PRIMARY KEY,
|
||||
book INTEGER NOT NULL,
|
||||
UNIQUE(book));
|
||||
CREATE TABLE preferences(id INTEGER PRIMARY KEY,
|
||||
key TEXT NON NULL,
|
||||
val TEXT NON NULL,
|
||||
UNIQUE(key));
|
||||
CREATE TABLE publishers ( id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
sort TEXT COLLATE NOCASE,
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE ratings ( id INTEGER PRIMARY KEY,
|
||||
rating INTEGER CHECK(rating > -1 AND rating < 11),
|
||||
UNIQUE (rating)
|
||||
);
|
||||
CREATE TABLE series ( id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
sort TEXT COLLATE NOCASE,
|
||||
UNIQUE (name)
|
||||
);
|
||||
CREATE TABLE tags ( id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL COLLATE NOCASE,
|
||||
UNIQUE (name)
|
||||
);
|
||||
CREATE VIEW meta AS
|
||||
SELECT id, title,
|
||||
(SELECT sortconcat(bal.id, name) FROM books_authors_link AS bal JOIN authors ON(author = authors.id) WHERE book = books.id) authors,
|
||||
(SELECT name FROM publishers WHERE publishers.id IN (SELECT publisher from books_publishers_link WHERE book=books.id)) publisher,
|
||||
(SELECT rating FROM ratings WHERE ratings.id IN (SELECT rating from books_ratings_link WHERE book=books.id)) rating,
|
||||
timestamp,
|
||||
(SELECT MAX(uncompressed_size) FROM data WHERE book=books.id) size,
|
||||
(SELECT concat(name) FROM tags WHERE tags.id IN (SELECT tag from books_tags_link WHERE book=books.id)) tags,
|
||||
(SELECT text FROM comments WHERE book=books.id) comments,
|
||||
(SELECT name FROM series WHERE series.id IN (SELECT series FROM books_series_link WHERE book=books.id)) series,
|
||||
series_index,
|
||||
sort,
|
||||
author_sort,
|
||||
(SELECT concat(format) FROM data WHERE data.book=books.id) formats,
|
||||
isbn,
|
||||
path,
|
||||
lccn,
|
||||
pubdate,
|
||||
flags,
|
||||
uuid
|
||||
FROM books;
|
||||
CREATE VIEW tag_browser_authors AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(id) FROM books_authors_link WHERE author=authors.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_authors_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.author=authors.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
sort AS sort
|
||||
FROM authors;
|
||||
CREATE VIEW tag_browser_filtered_authors AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_authors_link.id) FROM books_authors_link WHERE
|
||||
author=authors.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_authors_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.author=authors.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
sort AS sort
|
||||
FROM authors;
|
||||
CREATE VIEW tag_browser_filtered_publishers AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_publishers_link.id) FROM books_publishers_link WHERE
|
||||
publisher=publishers.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_publishers_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.publisher=publishers.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
name AS sort
|
||||
FROM publishers;
|
||||
CREATE VIEW tag_browser_filtered_ratings AS SELECT
|
||||
id,
|
||||
rating,
|
||||
(SELECT COUNT(books_ratings_link.id) FROM books_ratings_link WHERE
|
||||
rating=ratings.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_ratings_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.rating=ratings.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
rating AS sort
|
||||
FROM ratings;
|
||||
CREATE VIEW tag_browser_filtered_series AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_series_link.id) FROM books_series_link WHERE
|
||||
series=series.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_series_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.series=series.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
(title_sort(name)) AS sort
|
||||
FROM series;
|
||||
CREATE VIEW tag_browser_filtered_tags AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE
|
||||
tag=tags.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_tags_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.tag=tags.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
name AS sort
|
||||
FROM tags;
|
||||
CREATE VIEW tag_browser_publishers AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_publishers_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.publisher=publishers.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
name AS sort
|
||||
FROM publishers;
|
||||
CREATE VIEW tag_browser_ratings AS SELECT
|
||||
id,
|
||||
rating,
|
||||
(SELECT COUNT(id) FROM books_ratings_link WHERE rating=ratings.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_ratings_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.rating=ratings.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
rating AS sort
|
||||
FROM ratings;
|
||||
CREATE VIEW tag_browser_series AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(id) FROM books_series_link WHERE series=series.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_series_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.series=series.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
(title_sort(name)) AS sort
|
||||
FROM series;
|
||||
CREATE VIEW tag_browser_tags AS SELECT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(id) FROM books_tags_link WHERE tag=tags.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_tags_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.tag=tags.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
name AS sort
|
||||
FROM tags;
|
||||
CREATE INDEX authors_idx ON books (author_sort COLLATE NOCASE);
|
||||
CREATE INDEX books_authors_link_aidx ON books_authors_link (author);
|
||||
CREATE INDEX books_authors_link_bidx ON books_authors_link (book);
|
||||
CREATE INDEX books_idx ON books (sort COLLATE NOCASE);
|
||||
CREATE INDEX books_languages_link_aidx ON books_languages_link (lang_code);
|
||||
CREATE INDEX books_languages_link_bidx ON books_languages_link (book);
|
||||
CREATE INDEX books_publishers_link_aidx ON books_publishers_link (publisher);
|
||||
CREATE INDEX books_publishers_link_bidx ON books_publishers_link (book);
|
||||
CREATE INDEX books_ratings_link_aidx ON books_ratings_link (rating);
|
||||
CREATE INDEX books_ratings_link_bidx ON books_ratings_link (book);
|
||||
CREATE INDEX books_series_link_aidx ON books_series_link (series);
|
||||
CREATE INDEX books_series_link_bidx ON books_series_link (book);
|
||||
CREATE INDEX books_tags_link_aidx ON books_tags_link (tag);
|
||||
CREATE INDEX books_tags_link_bidx ON books_tags_link (book);
|
||||
CREATE INDEX comments_idx ON comments (book);
|
||||
CREATE INDEX conversion_options_idx_a ON conversion_options (format COLLATE NOCASE);
|
||||
CREATE INDEX conversion_options_idx_b ON conversion_options (book);
|
||||
CREATE INDEX custom_columns_idx ON custom_columns (label);
|
||||
CREATE INDEX data_idx ON data (book);
|
||||
CREATE INDEX formats_idx ON data (format);
|
||||
CREATE INDEX languages_idx ON languages (lang_code COLLATE NOCASE);
|
||||
CREATE INDEX publishers_idx ON publishers (name COLLATE NOCASE);
|
||||
CREATE INDEX series_idx ON series (name COLLATE NOCASE);
|
||||
CREATE INDEX tags_idx ON tags (name COLLATE NOCASE);
|
||||
CREATE TRIGGER books_delete_trg
|
||||
AFTER DELETE ON books
|
||||
BEGIN
|
||||
DELETE FROM books_authors_link WHERE book=OLD.id;
|
||||
DELETE FROM books_publishers_link WHERE book=OLD.id;
|
||||
DELETE FROM books_ratings_link WHERE book=OLD.id;
|
||||
DELETE FROM books_series_link WHERE book=OLD.id;
|
||||
DELETE FROM books_tags_link WHERE book=OLD.id;
|
||||
DELETE FROM books_languages_link WHERE book=OLD.id;
|
||||
DELETE FROM data WHERE book=OLD.id;
|
||||
DELETE FROM comments WHERE book=OLD.id;
|
||||
DELETE FROM conversion_options WHERE book=OLD.id;
|
||||
DELETE FROM books_plugin_data WHERE book=OLD.id;
|
||||
DELETE FROM identifiers WHERE book=OLD.id;
|
||||
END;
|
||||
CREATE TRIGGER books_insert_trg AFTER INSERT ON books
|
||||
BEGIN
|
||||
UPDATE books SET sort=title_sort(NEW.title),uuid=uuid4() WHERE id=NEW.id;
|
||||
END;
|
||||
CREATE TRIGGER books_update_trg
|
||||
AFTER UPDATE ON books
|
||||
BEGIN
|
||||
UPDATE books SET sort=title_sort(NEW.title)
|
||||
WHERE id=NEW.id AND OLD.title <> NEW.title;
|
||||
END;
|
||||
CREATE TRIGGER fkc_comments_insert
|
||||
BEFORE INSERT ON comments
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_comments_update
|
||||
BEFORE UPDATE OF book ON comments
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_data_insert
|
||||
BEFORE INSERT ON data
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_data_update
|
||||
BEFORE UPDATE OF book ON data
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_authors
|
||||
BEFORE DELETE ON authors
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT COUNT(id) FROM books_authors_link WHERE author=OLD.id) > 0
|
||||
THEN RAISE(ABORT, 'Foreign key violation: authors is still referenced')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_languages
|
||||
BEFORE DELETE ON languages
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT COUNT(id) FROM books_languages_link WHERE lang_code=OLD.id) > 0
|
||||
THEN RAISE(ABORT, 'Foreign key violation: language is still referenced')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_languages_link
|
||||
BEFORE INSERT ON books_languages_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from languages WHERE id=NEW.lang_code) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: lang_code not in languages')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_publishers
|
||||
BEFORE DELETE ON publishers
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=OLD.id) > 0
|
||||
THEN RAISE(ABORT, 'Foreign key violation: publishers is still referenced')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_series
|
||||
BEFORE DELETE ON series
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT COUNT(id) FROM books_series_link WHERE series=OLD.id) > 0
|
||||
THEN RAISE(ABORT, 'Foreign key violation: series is still referenced')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_delete_on_tags
|
||||
BEFORE DELETE ON tags
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT COUNT(id) FROM books_tags_link WHERE tag=OLD.id) > 0
|
||||
THEN RAISE(ABORT, 'Foreign key violation: tags is still referenced')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_insert_books_authors_link
|
||||
BEFORE INSERT ON books_authors_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from authors WHERE id=NEW.author) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: author not in authors')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_insert_books_publishers_link
|
||||
BEFORE INSERT ON books_publishers_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from publishers WHERE id=NEW.publisher) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: publisher not in publishers')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_insert_books_ratings_link
|
||||
BEFORE INSERT ON books_ratings_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from ratings WHERE id=NEW.rating) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: rating not in ratings')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_insert_books_series_link
|
||||
BEFORE INSERT ON books_series_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from series WHERE id=NEW.series) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: series not in series')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_insert_books_tags_link
|
||||
BEFORE INSERT ON books_tags_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
WHEN (SELECT id from tags WHERE id=NEW.tag) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: tag not in tags')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_authors_link_a
|
||||
BEFORE UPDATE OF book ON books_authors_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_authors_link_b
|
||||
BEFORE UPDATE OF author ON books_authors_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from authors WHERE id=NEW.author) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: author not in authors')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_languages_link_a
|
||||
BEFORE UPDATE OF book ON books_languages_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_languages_link_b
|
||||
BEFORE UPDATE OF lang_code ON books_languages_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from languages WHERE id=NEW.lang_code) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: lang_code not in languages')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_publishers_link_a
|
||||
BEFORE UPDATE OF book ON books_publishers_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_publishers_link_b
|
||||
BEFORE UPDATE OF publisher ON books_publishers_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from publishers WHERE id=NEW.publisher) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: publisher not in publishers')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_ratings_link_a
|
||||
BEFORE UPDATE OF book ON books_ratings_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_ratings_link_b
|
||||
BEFORE UPDATE OF rating ON books_ratings_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from ratings WHERE id=NEW.rating) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: rating not in ratings')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_series_link_a
|
||||
BEFORE UPDATE OF book ON books_series_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_series_link_b
|
||||
BEFORE UPDATE OF series ON books_series_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from series WHERE id=NEW.series) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: series not in series')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_tags_link_a
|
||||
BEFORE UPDATE OF book ON books_tags_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from books WHERE id=NEW.book) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: book not in books')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER fkc_update_books_tags_link_b
|
||||
BEFORE UPDATE OF tag ON books_tags_link
|
||||
BEGIN
|
||||
SELECT CASE
|
||||
WHEN (SELECT id from tags WHERE id=NEW.tag) IS NULL
|
||||
THEN RAISE(ABORT, 'Foreign key violation: tag not in tags')
|
||||
END;
|
||||
END;
|
||||
CREATE TRIGGER series_insert_trg
|
||||
AFTER INSERT ON series
|
||||
BEGIN
|
||||
UPDATE series SET sort=NEW.name WHERE id=NEW.id;
|
||||
END;
|
||||
CREATE TRIGGER series_update_trg
|
||||
AFTER UPDATE ON series
|
||||
BEGIN
|
||||
UPDATE series SET sort=NEW.name WHERE id=NEW.id;
|
||||
END;
|
||||
pragma user_version=21;
|
|
@ -3,13 +3,13 @@
|
|||
* PHP EPub Meta library
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @author Sébastien Lucas <sebastien@slucas.fr>
|
||||
* @author Sébastien Lucas <sebastien@slucas.fr>
|
||||
*/
|
||||
|
||||
|
||||
require_once(realpath( dirname( __FILE__ ) ) . '/tbszip.php');
|
||||
|
||||
define ("METADATA_FILE", "META-INF/container.xml");
|
||||
|
||||
|
||||
class EPub {
|
||||
public $xml; //FIXME change to protected, later
|
||||
public $toc;
|
||||
|
@ -26,12 +26,13 @@ class EPub {
|
|||
* Constructor
|
||||
*
|
||||
* @param string $file path to epub file to work on
|
||||
* @param string $zipClass class to handle zip
|
||||
* @throws Exception if metadata could not be loaded
|
||||
*/
|
||||
public function __construct($file){
|
||||
public function __construct($file, $zipClass = 'clsTbsZip'){
|
||||
// open file
|
||||
$this->file = $file;
|
||||
$this->zip = new clsTbsZip();
|
||||
$this->zip = new $zipClass();
|
||||
if(!$this->zip->Open($this->file)){
|
||||
throw new Exception('Failed to read epub file');
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ class EPub {
|
|||
if (!$this->zip->FileExists(METADATA_FILE)) {
|
||||
throw new Exception ("Unable to find metadata.xml");
|
||||
}
|
||||
|
||||
|
||||
$data = $this->zip->FileRead(METADATA_FILE);
|
||||
if($data == false){
|
||||
throw new Exception('Failed to access epub container data');
|
||||
|
@ -56,7 +57,7 @@ class EPub {
|
|||
if (!$this->zip->FileExists($this->meta)) {
|
||||
throw new Exception ("Unable to find " . $this->meta);
|
||||
}
|
||||
|
||||
|
||||
$data = $this->zip->FileRead($this->meta);
|
||||
if(!$data){
|
||||
throw new Exception('Failed to access epub metadata');
|
||||
|
@ -67,24 +68,24 @@ class EPub {
|
|||
$this->xml->formatOutput = true;
|
||||
$this->xpath = new EPubDOMXPath($this->xml);
|
||||
}
|
||||
|
||||
|
||||
public function initSpineComponent ()
|
||||
{
|
||||
$spine = $this->xpath->query('//opf:spine')->item(0);
|
||||
$tocid = $spine->getAttribute('toc');
|
||||
$tochref = $this->xpath->query("//opf:manifest/opf:item[@id='$tocid']")->item(0)->attr('href');
|
||||
$tocpath = dirname($this->meta).'/'.$tochref;
|
||||
$tocpath = dirname($this->meta).'/'.$tochref;
|
||||
// read epub toc
|
||||
if (!$this->zip->FileExists($tocpath)) {
|
||||
throw new Exception ("Unable to find " . $tocpath);
|
||||
}
|
||||
|
||||
|
||||
$data = $this->zip->FileRead($tocpath);
|
||||
$this->toc = new DOMDocument();
|
||||
$this->toc->registerNodeClass('DOMElement','EPubDOMElement');
|
||||
$this->toc->loadXML($data);
|
||||
$this->toc_xpath = new EPubDOMXPath($this->toc);
|
||||
$rootNamespace = $this->toc->lookupNamespaceUri($this->toc->namespaceURI);
|
||||
$rootNamespace = $this->toc->lookupNamespaceUri($this->toc->namespaceURI);
|
||||
$this->toc_xpath->registerNamespace('x', $rootNamespace);
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ class EPub {
|
|||
public function file(){
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the epub file
|
||||
*/
|
||||
|
@ -123,7 +124,7 @@ class EPub {
|
|||
$this->download ();
|
||||
$this->zip->close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the updated epub
|
||||
*/
|
||||
|
@ -149,7 +150,7 @@ class EPub {
|
|||
}
|
||||
return $spine;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the component content
|
||||
*/
|
||||
|
@ -158,13 +159,13 @@ class EPub {
|
|||
if (!$this->zip->FileExists($path)) {
|
||||
throw new Exception ("Unable to find " . $path);
|
||||
}
|
||||
|
||||
|
||||
$data = $this->zip->FileRead($path);
|
||||
$data = preg_replace ("/src=[\"']([\w\/\.]*?)[\"']/", "src='epubfs.php?comp=$1'", $data);
|
||||
$data = preg_replace ("/href=[\"']([\w\/\.]*?)[\"']/", "href='epubfs.php?comp=$1'", $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the component content type
|
||||
*/
|
||||
|
@ -187,7 +188,7 @@ class EPub {
|
|||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get or set the book author(s)
|
||||
|
@ -302,6 +303,37 @@ class EPub {
|
|||
return $this->getset('dc:description',$description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get the book's Unique Identifier
|
||||
*
|
||||
* @param string Unique identifier
|
||||
*/
|
||||
public function Uuid($uuid = false)
|
||||
{
|
||||
$nodes = $this->xpath->query('/opf:package');
|
||||
if ($nodes->length !== 1) {
|
||||
$error = sprintf('Cannot find ebook identifier');
|
||||
throw new Exception($error);
|
||||
}
|
||||
$identifier = $nodes->item(0)->attr('unique-identifier');
|
||||
|
||||
$res = $this->getset('dc:identifier', $uuid, 'id', $identifier);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get the book's URI
|
||||
*
|
||||
* @param string URI
|
||||
*/
|
||||
public function Uri($uri = false)
|
||||
{
|
||||
$res = $this->getset('dc:identifier', $uri, 'opf:scheme', 'URI');
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get the book's ISBN number
|
||||
*
|
||||
|
@ -328,7 +360,7 @@ class EPub {
|
|||
public function Amazon($amazon=false){
|
||||
return $this->getset('dc:identifier',$amazon,'opf:scheme','AMAZON');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set or get the Calibre UUID of the book
|
||||
*
|
||||
|
@ -346,7 +378,7 @@ class EPub {
|
|||
public function Serie($serie=false){
|
||||
return $this->getset('opf:meta',$serie,'name','calibre:series','content');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set or get the Serie Index of the book
|
||||
*
|
||||
|
@ -355,7 +387,7 @@ class EPub {
|
|||
public function SerieIndex($serieIndex=false){
|
||||
return $this->getset('opf:meta',$serieIndex,'name','calibre:series_index','content');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set or get the book's subjects (aka. tags)
|
||||
*
|
||||
|
@ -476,11 +508,11 @@ class EPub {
|
|||
'found' => $path
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function getCoverItem () {
|
||||
$nodes = $this->xpath->query('//opf:metadata/opf:meta[@name="cover"]');
|
||||
if(!$nodes->length) return NULL;
|
||||
|
||||
|
||||
$coverid = (String) $nodes->item(0)->attr('opf:content');
|
||||
if(!$coverid) return NULL;
|
||||
|
||||
|
@ -489,14 +521,14 @@ class EPub {
|
|||
|
||||
return $nodes->item(0);
|
||||
}
|
||||
|
||||
|
||||
public function updateForKepub () {
|
||||
$item = $this->getCoverItem ();
|
||||
if (!is_null ($item)) {
|
||||
$item->attr('opf:properties', 'cover-image');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function Cover2($path=false, $mime=false){
|
||||
$hascover = true;
|
||||
$item = $this->getCoverItem ();
|
||||
|
@ -509,7 +541,7 @@ class EPub {
|
|||
$this->coverpath = ltrim($this->coverpath,'\\');
|
||||
$this->coverpath = ltrim($this->coverpath,'/');
|
||||
}
|
||||
|
||||
|
||||
// set cover
|
||||
if($path !== false){
|
||||
if (!$hascover) return; // TODO For now only update
|
||||
|
@ -523,7 +555,7 @@ class EPub {
|
|||
|
||||
$this->reparse();
|
||||
}
|
||||
|
||||
|
||||
if (!$hascover) return $this->no_cover();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue