Completed
Pull Request — master (#233)
by
unknown
06:40
created

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * COPS (Calibre OPDS PHP Server) class file
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     S�bastien Lucas <[email protected]>
7
 */
8
9
define ("VERSION", "1.0.0RC4");
10
define ("DB", "db");
11
date_default_timezone_set($config['default_timezone']);
12
13
require_once('virtuallib.php');
14
15
16
function useServerSideRendering () {
17 3
    global $config;
18 3
    return preg_match("/" . $config['cops_server_side_render'] . "/", $_SERVER['HTTP_USER_AGENT']);
19
}
20
21
function serverSideRender ($data) {
22
    // Get the templates
23 2
    $theme = getCurrentTemplate ();
24 2
    $header = file_get_contents('templates/' . $theme . '/header.html');
25 2
    $footer = file_get_contents('templates/' . $theme . '/footer.html');
26 2
    $main = file_get_contents('templates/' . $theme . '/main.html');
27 2
    $bookdetail = file_get_contents('templates/' . $theme . '/bookdetail.html');
28 2
    $page = file_get_contents('templates/' . $theme . '/page.html');
29
30
    // Generate the function for the template
31 2
    $template = new doT ();
32 2
    $dot = $template->template ($page, array ("bookdetail" => $bookdetail,
33 2
                                              "header" => $header,
34 2
                                              "footer" => $footer,
35 2
                                              "main" => $main));
36
    // If there is a syntax error in the function created
37
    // $dot will be equal to FALSE
38 2
    if (!$dot) {
39
        return FALSE;
40
    }
41
    // Execute the template
42 2
    if (!empty ($data)) {
43
        return $dot ($data);
44
    }
45
46 2
    return NULL;
47
}
48
49
function getQueryString () {
50 18
    if ( isset($_SERVER['QUERY_STRING']) ) {
51 16
        return $_SERVER['QUERY_STRING'];
52
    }
53 2
    return "";
54
}
55
56
function notFound () {
57
    header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
58
    header("Status: 404 Not Found");
59
60
    $_SERVER['REDIRECT_STATUS'] = 404;
61
}
62
63
function getURLParam ($name, $default = NULL) {
64 101
    if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") {
65 24
        return $_GET[$name];
66
    }
67 101
    return $default;
68
}
69
70
function getCurrentOption ($option) {
71 87
    global $config;
72 87
    if (isset($_COOKIE[$option])) {
73 2
        if (isset($config ["cops_" . $option]) && is_array ($config ["cops_" . $option])) {
74
            return explode (",", $_COOKIE[$option]);
75
        } else {
76 2
            return $_COOKIE[$option];
77
        }
78
    }
79 85
    if ($option == "style") {
80 2
        return "default";
81
    }
82
83 85
    if (isset($config ["cops_" . $option])) {
84 85
        return $config ["cops_" . $option];
85
    }
86
87
    return "";
88
}
89
90
function getCurrentCss () {
91 2
    return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css";
92
}
93
94
function getCurrentTemplate () {
95 4
    return getCurrentOption ("template");
96
}
97
98
function getUrlWithVersion ($url) {
99 50
    return $url . "?v=" . VERSION;
100
}
101
102
function xml2xhtml($xml) {
103 35
    return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', create_function('$m', '
104
        $xhtml_tags = array("br", "hr", "input", "frame", "img", "area", "link", "col", "base", "basefont", "param");
105
        return in_array($m[1], $xhtml_tags) ? "<$m[1]$m[2] />" : "<$m[1]$m[2]></$m[1]>";
106 35
    '), $xml);
107
}
108
109
function display_xml_error($error)
110
{
111
    $return = "";
112
    $return .= str_repeat('-', $error->column) . "^\n";
113
114
    switch ($error->level) {
115
        case LIBXML_ERR_WARNING:
116
            $return .= "Warning $error->code: ";
117
            break;
118
         case LIBXML_ERR_ERROR:
119
            $return .= "Error $error->code: ";
120
            break;
121
        case LIBXML_ERR_FATAL:
122
            $return .= "Fatal Error $error->code: ";
123
            break;
124
    }
125
126
    $return .= trim($error->message) .
127
               "\n  Line: $error->line" .
128
               "\n  Column: $error->column";
129
130
    if ($error->file) {
131
        $return .= "\n  File: $error->file";
132
    }
133
134
    return "$return\n\n--------------------------------------------\n\n";
135
}
136
137
function are_libxml_errors_ok ()
138
{
139 35
    $errors = libxml_get_errors();
140
141 35
    foreach ($errors as $error) {
142
        if ($error->code == 801) return false;
143 35
    }
144 35
    return true;
145
}
146
147
function html2xhtml ($html) {
148 35
    $doc = new DOMDocument();
149 35
    libxml_use_internal_errors(true);
150
151 35
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
152 35
                        $html  . '</body></html>'); // Load the HTML
153 35
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
154 35
    $output = xml2xhtml($output);
155 35
    if (preg_match ('#<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></meta></head><body>(.*)</body></html>#ms', $output, $matches)) {
156 35
        $output = $matches [1]; // Remove <html><body>
157 35
    }
158
    /*
159
    // In case of error with summary, use it to debug
160
    $errors = libxml_get_errors();
161
162
    foreach ($errors as $error) {
163
        $output .= display_xml_error($error);
164
    }
165
    */
166
167 35
    if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
168
169 35
    libxml_use_internal_errors(false);
170 35
    return $output;
171
}
172
173
/**
174
 * This method is a direct copy-paste from
175
 * http://tmont.com/blargh/2010/1/string-format-in-php
176
 */
177
function str_format($format) {
0 ignored issues
show
The parameter $format is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
178 94
    $args = func_get_args();
179 94
    $format = array_shift($args);
180
181 94
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
182 94
    $offset = 0;
183 94
    foreach ($matches[1] as $data) {
184 94
        $i = $data[0];
185 94
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
186 94
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
187 94
    }
188
189 94
    return $format;
190
}
191
192
/**
193
 * Get all accepted languages from the browser and put them in a sorted array
194
 * languages id are normalized : fr-fr -> fr_FR
195
 * @return array of languages
196
 */
197
function getAcceptLanguages() {
198 16
    $langs = array();
199
200 16
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
201
        // break up string into pieces (languages and q factors)
202 16
        $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
203 16
        if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) {
204
            // Special fix for IE11 which send fr-FR and nothing else
205 3
            $accept = $accept . "," . $matches[1] . ";q=0.8";
206 3
        }
207 16
        preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $accept, $lang_parse);
208
209 16
        if (count($lang_parse[1])) {
210 16
            $langs = array();
211 16
            foreach ($lang_parse[1] as $lang) {
212
                // Format the language code (not standard among browsers)
213 16
                if (strlen($lang) == 5) {
214 11
                    $lang = str_replace("-", "_", $lang);
215 11
                    $splitted = preg_split("/_/", $lang);
216 11
                    $lang = $splitted[0] . "_" . strtoupper($splitted[1]);
217 11
                }
218 16
                array_push($langs, $lang);
219 16
            }
220
            // create a list like "en" => 0.8
221 16
            $langs = array_combine($langs, $lang_parse[4]);
222
223
            // set default to 1 for any without q factor
224 16
            foreach ($langs as $lang => $val) {
225 16
                if ($val === '') $langs[$lang] = 1;
226 16
            }
227
228
            // sort list based on value
229 16
            arsort($langs, SORT_NUMERIC);
230 16
        }
231 16
    }
232
233 16
    return $langs;
234
}
235
236
/**
237
 * Find the best translation file possible based on the accepted languages
238
 * @return array of language and language file
239
 */
240
function getLangAndTranslationFile() {
241 17
    global $config;
242 17
    $langs = array();
243 17
    $lang = "en";
244 17
    if (!empty($config['cops_language'])) {
245
        $lang = $config['cops_language'];
246
    }
247 17
    elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
248 16
        $langs = getAcceptLanguages();
249 16
    }
250
    //echo var_dump($langs);
251 17
    $lang_file = NULL;
252 17
    foreach ($langs as $language => $val) {
253 16
        $temp_file = dirname(__FILE__). '/lang/Localization_' . $language . '.json';
254 16
        if (file_exists($temp_file)) {
255 16
            $lang = $language;
256 16
            $lang_file = $temp_file;
257 16
            break;
258
        }
259 17
    }
260 17
    if (empty ($lang_file)) {
261 3
        $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
262 3
    }
263 17
    return array($lang, $lang_file);
264
}
265
266
/**
267
 * This method is based on this page
268
 * http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/
269
 */
270
function localize($phrase, $count=-1, $reset=false) {
271 114
    global $config;
272 114
    if ($count == 0)
273 114
        $phrase .= ".none";
274 114
    if ($count == 1)
275 114
        $phrase .= ".one";
276 114
    if ($count > 1)
277 114
        $phrase .= ".many";
278
279
    /* Static keyword is used to ensure the file is loaded only once */
280 114
    static $translations = NULL;
281 114
    if ($reset) {
282 16
        $translations = NULL;
283 16
    }
284
    /* If no instance of $translations has occured load the language file */
285 114
    if (is_null($translations)) {
286 17
        $lang_file_en = NULL;
287 17
        list ($lang, $lang_file) = getLangAndTranslationFile();
288 17
        if ($lang != "en") {
289 1
            $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
290 1
        }
291
292 17
        $lang_file_content = file_get_contents($lang_file);
293
        /* Load the language file as a JSON object and transform it into an associative array */
294 17
        $translations = json_decode($lang_file_content, true);
295
296
        /* Clean the array of all unfinished translations */
297 17
        foreach (array_keys ($translations) as $key) {
298 17
            if (preg_match ("/^##TODO##/", $key)) {
299 1
                unset ($translations [$key]);
300 1
            }
301 17
        }
302
        if ($lang_file_en)
0 ignored issues
show
Bug Best Practice introduced by
The expression $lang_file_en of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
303 17
        {
304 1
            $lang_file_content = file_get_contents($lang_file_en);
305 1
            $translations_en = json_decode($lang_file_content, true);
306 1
            $translations = array_merge ($translations_en, $translations);
307 1
        }
308 17
    }
309 114
    if (array_key_exists ($phrase, $translations)) {
310 114
        return $translations[$phrase];
311
    }
312 1
    return $phrase;
313
}
314
315
function addURLParameter($urlParams, $paramName, $paramValue) {
316 58
    if (empty ($urlParams)) {
317 48
        $urlParams = "";
318 48
    }
319 58
    $start = "";
320 58
    if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
321 15
        $start = "?";
322 15
        $urlParams = $matches[1];
323 15
    }
324 58
    $params = array();
325 58
    parse_str($urlParams, $params);
326 58
    if (empty ($paramValue) && $paramValue != 0) {
327
        unset ($params[$paramName]);
328
    } else {
329 58
        $params[$paramName] = $paramValue;
330
    }
331 58
    return $start . http_build_query($params);
332
}
333
334
function useNormAndUp () {
335 107
    global $config;
336 107
    return $config ['cops_normalized_search'] == "1";
337
}
338
339
function normalizeUtf8String( $s) {
340 8
    include_once 'transliteration.php';
341 8
    return _transliteration_process($s);
342
}
343
344
function normAndUp ($s) {
345 7
    return mb_strtoupper (normalizeUtf8String($s), 'UTF-8');
346
}
347
348
class Link
349
{
350
    const OPDS_THUMBNAIL_TYPE = "http://opds-spec.org/image/thumbnail";
351
    const OPDS_IMAGE_TYPE = "http://opds-spec.org/image";
352
    const OPDS_ACQUISITION_TYPE = "http://opds-spec.org/acquisition";
353
    const OPDS_NAVIGATION_TYPE = "application/atom+xml;profile=opds-catalog;kind=navigation";
354
    const OPDS_PAGING_TYPE = "application/atom+xml;profile=opds-catalog;kind=acquisition";
355
356
    public $href;
357
    public $type;
358
    public $rel;
359
    public $title;
360
    public $facetGroup;
361
    public $activeFacet;
362
363 96
    public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
364 96
        $this->href = $phref;
365 96
        $this->type = $ptype;
366 96
        $this->rel = $prel;
367 96
        $this->title = $ptitle;
368 96
        $this->facetGroup = $pfacetGroup;
369 96
        $this->activeFacet = $pactiveFacet;
370 96
    }
371
372 10
    public function hrefXhtml () {
373 10
        return $this->href;
374
    }
375
}
376
377
class LinkNavigation extends Link
378
{
379 95
    public function __construct($phref, $prel = NULL, $ptitle = NULL) {
380 95
        parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
381 95
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
382 95
        if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
383 95
        if (preg_match ("/(bookdetail|getJSON).php/", $_SERVER["SCRIPT_NAME"])) {
384
            $this->href = "index.php" . $this->href;
385
        } else {
386 95
            $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
387
        }
388 95
    }
389
}
390
391
class LinkFacet extends Link
392
{
393 1
    public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
394 1
        parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet);
395 1
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
396 1
        $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
397 1
    }
398
}
399
400
class Entry
401
{
402
    public $title;
403
    public $id;
404
    public $content;
405
    public $numberOfElement;
406
    public $contentType;
407
    public $linkArray;
408
    public $localUpdated;
409
    public $className;
410
    private static $updated = NULL;
411
412
    public static $icons = array(
413
        Author::ALL_AUTHORS_ID       => 'images/author.png',
414
        Serie::ALL_SERIES_ID         => 'images/serie.png',
415
        Book::ALL_RECENT_BOOKS_ID    => 'images/recent.png',
416
        Tag::ALL_TAGS_ID             => 'images/tag.png',
417
        Language::ALL_LANGUAGES_ID   => 'images/language.png',
418
        CustomColumn::ALL_CUSTOMS_ID => 'images/tag.png',
419
        "cops:books$"             => 'images/allbook.png',
420
        "cops:books:letter"       => 'images/allbook.png',
421
        Publisher::ALL_PUBLISHERS_ID => 'images/publisher.png'
422
    );
423
424
    public function getUpdatedTime () {
425
        if (!is_null ($this->localUpdated)) {
426
            return date (DATE_ATOM, $this->localUpdated);
427
        }
428
        if (is_null (self::$updated)) {
429
            self::$updated = time();
430
        }
431
        return date (DATE_ATOM, self::$updated);
432
    }
433
434 7
    public function getNavLink () {
435 7
        foreach ($this->linkArray as $link) {
436 7
            if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
437
438 7
            return $link->hrefXhtml ();
439
        }
440
        return "#";
441
    }
442
443 89
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) {
444 89
        global $config;
445 89
        $this->title = $ptitle;
446 89
        $this->id = $pid;
447 89
        $this->content = $pcontent;
448 89
        $this->contentType = $pcontentType;
449 89
        $this->linkArray = $plinkArray;
450 89
        $this->className = $pclass;
451 89
        $this->numberOfElement = $pcount;
452
453 89
        if ($config['cops_show_icons'] == 1)
454 89
        {
455 89
            foreach (self::$icons as $reg => $image)
456
            {
457 89
                if (preg_match ("/" . $reg . "/", $pid)) {
458 50
                    array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE));
459 50
                    break;
460
                }
461 89
            }
462 89
        }
463
464 89
        if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $this->id);
465 89
    }
466
}
467
468
class EntryBook extends Entry
469
{
470
    public $book;
471
472 39
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) {
473 39
        parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray);
474 39
        $this->book = $pbook;
475 39
        $this->localUpdated = $pbook->timestamp;
476 39
    }
477
478
    public function getCoverThumbnail () {
479
        foreach ($this->linkArray as $link) {
480
            if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
481
                return $link->hrefXhtml ();
482
        }
483
        return null;
484
    }
485
486
    public function getCover () {
487
        foreach ($this->linkArray as $link) {
488
            if ($link->rel == Link::OPDS_IMAGE_TYPE)
489
                return $link->hrefXhtml ();
490
        }
491
        return null;
492
    }
493
}
494
495
class Page
496
{
497
    public $title;
498
    public $subtitle = "";
499
    public $authorName = "";
500
    public $authorUri = "";
501
    public $authorEmail = "";
502
    public $idPage;
503
    public $idGet;
504
    public $query;
505
    public $favicon;
506
    public $n;
507
    public $book;
508
    public $totalNumber = -1;
509
    public $entryArray = array();
510
511 81
    public static function getPage ($pageId, $id, $query, $n)
512
    {
513
        switch ($pageId) {
514 81
            case Base::PAGE_ALL_AUTHORS :
515 3
                return new PageAllAuthors ($id, $query, $n);
516 78
            case Base::PAGE_AUTHORS_FIRST_LETTER :
517 1
                return new PageAllAuthorsLetter ($id, $query, $n);
518 77
            case Base::PAGE_AUTHOR_DETAIL :
519 7
                return new PageAuthorDetail ($id, $query, $n);
520 70
            case Base::PAGE_ALL_TAGS :
521 2
                return new PageAllTags ($id, $query, $n);
522 68
            case Base::PAGE_TAG_DETAIL :
523 1
                return new PageTagDetail ($id, $query, $n);
524 67
            case Base::PAGE_ALL_LANGUAGES :
525 2
                return new PageAllLanguages ($id, $query, $n);
526 65
            case Base::PAGE_LANGUAGE_DETAIL :
527 1
                return new PageLanguageDetail ($id, $query, $n);
528 64
            case Base::PAGE_ALL_CUSTOMS :
529 3
                return new PageAllCustoms ($id, $query, $n);
530 61
            case Base::PAGE_CUSTOM_DETAIL :
531 3
                return new PageCustomDetail ($id, $query, $n);
532 58
            case Base::PAGE_ALL_RATINGS :
533 1
                return new PageAllRating ($id, $query, $n);
534 57
            case Base::PAGE_RATING_DETAIL :
535 1
                return new PageRatingDetail ($id, $query, $n);
536 56
            case Base::PAGE_ALL_SERIES :
537 2
                return new PageAllSeries ($id, $query, $n);
538 54
            case Base::PAGE_ALL_BOOKS :
539 3
                return new PageAllBooks ($id, $query, $n);
540 51
            case Base::PAGE_ALL_BOOKS_LETTER:
541 1
                return new PageAllBooksLetter ($id, $query, $n);
542 50
            case Base::PAGE_ALL_RECENT_BOOKS :
543 4
                return new PageRecentBooks ($id, $query, $n);
544 46
            case Base::PAGE_SERIE_DETAIL :
545 1
                return new PageSerieDetail ($id, $query, $n);
546 45
            case Base::PAGE_OPENSEARCH_QUERY :
547 31
                return new PageQueryResult ($id, $query, $n);
548 14
            case Base::PAGE_BOOK_DETAIL :
549 1
                return new PageBookDetail ($id, $query, $n);
550 13
            case Base::PAGE_ALL_PUBLISHERS:
551 2
                return new PageAllPublishers ($id, $query, $n);
552 11
            case Base::PAGE_PUBLISHER_DETAIL :
553 1
                return new PagePublisherDetail ($id, $query, $n);
554 10
            case Base::PAGE_ABOUT :
555
                return new PageAbout ($id, $query, $n);
556 10
            case Base::PAGE_CUSTOMIZE :
557
                return new PageCustomize ($id, $query, $n);
558 10
            default:
559 10
                $page = new Page ($id, $query, $n);
560 10
                $page->idPage = "cops:catalog";
561 10
                return $page;
562 10
        }
563
    }
564
565 81
    public function __construct($pid, $pquery, $pn) {
566 81
        global $config;
567
568 81
        $this->idGet = $pid;
569 81
        $this->query = $pquery;
570 81
        $this->n = $pn;
571 81
        $this->favicon = $config['cops_icon'];
572 81
        $this->authorName = empty($config['cops_author_name']) ? utf8_encode('S�bastien Lucas') : $config['cops_author_name'];
573 81
        $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri'];
574 81
        $this->authorEmail = empty($config['cops_author_email']) ? '[email protected]' : $config['cops_author_email'];
575 81
    }
576
577 10
    public function InitializeContent ()
578
    {
579 10
        global $config;
580 10
        $this->title = $config['cops_title_default'];
581 10
        $this->subtitle = $config['cops_subtitle_default'];
582 10
        if (Base::noDatabaseSelected ()) {
583 2
            $i = 0;
584 2
            foreach (Base::getDbNameList () as $key) {
585 2
            	if (VirtualLib::isVLEnabled()) {
586
            		// Virtual Libraries are enabled show each virtual library as one database
587
            		$nBooks = Book::getBookCount ($i);
588
            		foreach (VirtualLib::getVLNameList($i) as $vlName)
589
            			array_push ($this->entryArray, new Entry (str_format('{0} - {1}', $key, $vlName),
590
            								"cops:{$i}:catalog",
591
            								str_format (localize ("bookword", $nBooks), $nBooks), "text",
592
            								array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks));
593
            	} else {
594
            		// Virtual Libraries are enabled show each virtual library as one database
595 2
            		$nBooks = Book::getBookCount ($i);
596 2
	                array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog",
597 2
	                                        str_format (localize ("bookword", $nBooks), $nBooks), "text",
598 2
	                                        array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks));
599
            	}
600 2
                $i++;
601 2
                Base::clearDb ();
602 2
            }
603 2
        } else {
604 8
            if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) {
605 7
                array_push ($this->entryArray, Author::getCount());
606 7
            }
607 8
            if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) {
608 7
                $series = Serie::getCount();
609 7
                if (!is_null ($series)) array_push ($this->entryArray, $series);
610 7
            }
611 8
            if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) {
612 7
                $publisher = Publisher::getCount();
613 7
                if (!is_null ($publisher)) array_push ($this->entryArray, $publisher);
614 7
            }
615 8
            if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) {
616 7
                $tags = Tag::getCount();
617 7
                if (!is_null ($tags)) array_push ($this->entryArray, $tags);
618 7
            }
619 8
            if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) {
620 8
                $rating = Rating::getCount();
621 8
                if (!is_null ($rating)) array_push ($this->entryArray, $rating);
622 8
            }
623 8
            if (!in_array ("language", getCurrentOption ('ignored_categories'))) {
624 7
                $languages = Language::getCount();
625 7
                if (!is_null ($languages)) array_push ($this->entryArray, $languages);
626 7
            }
627 8
            foreach ($config['cops_calibre_custom_column'] as $lookup) {
628 4
                $customId = CustomColumn::getCustomId ($lookup);
629 4
                if (!is_null ($customId)) {
630 4
                    array_push ($this->entryArray, CustomColumn::getCount($customId));
631 4
                }
632 8
            }
633 8
            $this->entryArray = array_merge ($this->entryArray, Book::getCount());
634
635 8
            if (Base::isMultipleDatabaseEnabled ()) $this->title =  Base::getDbName ();
636
        }
637 10
    }
638
639 17
    public function isPaginated ()
640
    {
641 17
        return (getCurrentOption ("max_item_per_page") != -1 &&
642 17
                $this->totalNumber != -1 &&
643 17
                $this->totalNumber > getCurrentOption ("max_item_per_page"));
644
    }
645
646 2
    public function getNextLink ()
647
    {
648 2
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
649 2
        if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) {
650 1
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate"));
651
        }
652 1
        return NULL;
653
    }
654
655 2
    public function getPrevLink ()
656
    {
657 2
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
658 2
        if ($this->n > 1) {
659 1
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate"));
660
        }
661 2
        return NULL;
662
    }
663
664 2
    public function getMaxPage ()
665
    {
666 2
        return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page"));
667
    }
668
669 70
    public function containsBook ()
670
    {
671 70
        if (count ($this->entryArray) == 0) return false;
672 68
        if (get_class ($this->entryArray [0]) == "EntryBook") return true;
673 46
        return false;
674
    }
675
}
676
677
class PageAllAuthors extends Page
678
{
679 3
    public function InitializeContent ()
680
    {
681 3
        $this->title = localize("authors.title");
682 3
        if (getCurrentOption ("author_split_first_letter") == 1) {
683 2
            $this->entryArray = Author::getAllAuthorsByFirstLetter();
684 2
        }
685
        else {
686 1
            $this->entryArray = Author::getAllAuthors();
687
        }
688 3
        $this->idPage = Author::ALL_AUTHORS_ID;
689 3
    }
690
}
691
692
class PageAllAuthorsLetter extends Page
693
{
694 1
    public function InitializeContent ()
695
    {
696 1
        $this->idPage = Author::getEntryIdByLetter ($this->idGet);
697 1
        $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet);
698 1
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet);
699 1
    }
700
}
701
702
class PageAuthorDetail extends Page
703
{
704 7
    public function InitializeContent ()
705
    {
706 7
        $author = Author::getAuthorById ($this->idGet);
707 7
        $this->idPage = $author->getEntryId ();
708 7
        $this->title = $author->name;
709 7
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n);
710 7
    }
711
}
712
713
class PageAllPublishers extends Page
714
{
715 2
    public function InitializeContent ()
716
    {
717 2
        $this->title = localize("publishers.title");
718 2
        $this->entryArray = Publisher::getAllPublishers();
719 2
        $this->idPage = Publisher::ALL_PUBLISHERS_ID;
720 2
    }
721
}
722
723
class PagePublisherDetail extends Page
724
{
725 1
    public function InitializeContent ()
726
    {
727 1
        $publisher = Publisher::getPublisherById ($this->idGet);
728 1
        $this->title = $publisher->name;
729 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n);
730 1
        $this->idPage = $publisher->getEntryId ();
731 1
    }
732
}
733
734
class PageAllTags extends Page
735
{
736 2
    public function InitializeContent ()
737
    {
738 2
        $this->title = localize("tags.title");
739 2
        $this->entryArray = Tag::getAllTags();
740 2
        $this->idPage = Tag::ALL_TAGS_ID;
741 2
    }
742
}
743
744
class PageAllLanguages extends Page
745
{
746 2
    public function InitializeContent ()
747
    {
748 2
        $this->title = localize("languages.title");
749 2
        $this->entryArray = Language::getAllLanguages();
750 2
        $this->idPage = Language::ALL_LANGUAGES_ID;
751 2
    }
752
}
753
754
class PageCustomDetail extends Page
755
{
756 3
    public function InitializeContent ()
757
    {
758 3
        $customId = getURLParam ("custom", NULL);
759 3
        $custom = CustomColumn::getCustomById ($customId, $this->idGet);
760 3
        $this->idPage = $custom->getEntryId ();
761 3
        $this->title = $custom->name;
762 3
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($customId, $this->idGet, $this->n);
763 3
    }
764
}
765
766
class PageAllCustoms extends Page
767
{
768 3
    public function InitializeContent ()
769
    {
770 3
        $customId = getURLParam ("custom", NULL);
771 3
        $this->title = CustomColumn::getAllTitle ($customId);
772 3
        $this->entryArray = CustomColumn::getAllCustoms($customId);
773 3
        $this->idPage = CustomColumn::getAllCustomsId ($customId);
774 3
    }
775
}
776
777
class PageTagDetail extends Page
778
{
779 1
    public function InitializeContent ()
780
    {
781 1
        $tag = Tag::getTagById ($this->idGet);
782 1
        $this->idPage = $tag->getEntryId ();
783 1
        $this->title = $tag->name;
784 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n);
785 1
    }
786
}
787
788
class PageLanguageDetail extends Page
789
{
790 1
    public function InitializeContent ()
791
    {
792 1
        $language = Language::getLanguageById ($this->idGet);
793 1
        $this->idPage = $language->getEntryId ();
794 1
        $this->title = $language->lang_code;
795 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n);
796 1
    }
797
}
798
799
class PageAllSeries extends Page
800
{
801 2
    public function InitializeContent ()
802
    {
803 2
        $this->title = localize("series.title");
804 2
        $this->entryArray = Serie::getAllSeries();
805 2
        $this->idPage = Serie::ALL_SERIES_ID;
806 2
    }
807
}
808
809
class PageSerieDetail extends Page
810
{
811 1
    public function InitializeContent ()
812
    {
813 1
        $serie = Serie::getSerieById ($this->idGet);
814 1
        $this->title = $serie->name;
815 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n);
816 1
        $this->idPage = $serie->getEntryId ();
817 1
    }
818
}
819
820
class PageAllRating extends Page
821
{
822 1
    public function InitializeContent ()
823
    {
824 1
        $this->title = localize("ratings.title");
825 1
        $this->entryArray = Rating::getAllRatings();
826 1
        $this->idPage = Rating::ALL_RATING_ID;
827 1
    }
828
}
829
830
class PageRatingDetail extends Page
831
{
832 1
    public function InitializeContent ()
833
    {
834 1
        $rating = Rating::getRatingById ($this->idGet);
835 1
        $this->idPage = $rating->getEntryId ();
836 1
        $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2);
837 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n);
838 1
    }
839
}
840
841
class PageAllBooks extends Page
842
{
843 3
    public function InitializeContent ()
844
    {
845 3
        $this->title = localize ("allbooks.title");
846 3
        if (getCurrentOption ("titles_split_first_letter") == 1) {
847 2
            $this->entryArray = Book::getAllBooks();
848 2
        }
849
        else {
850 1
            list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n);
851
        }
852 3
        $this->idPage = Book::ALL_BOOKS_ID;
853 3
    }
854
}
855
856
class PageAllBooksLetter extends Page
857
{
858 1
    public function InitializeContent ()
859
    {
860 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n);
861 1
        $this->idPage = Book::getEntryIdByLetter ($this->idGet);
862
863 1
        $count = $this->totalNumber;
864 1
        if ($count == -1)
865 1
            $count = count ($this->entryArray);
866
867 1
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet);
868 1
    }
869
}
870
871
class PageRecentBooks extends Page
872
{
873 4
    public function InitializeContent ()
874
    {
875 4
        $this->title = localize ("recent.title");
876 4
        $this->entryArray = Book::getAllRecentBooks ();
877 4
        $this->idPage = Book::ALL_RECENT_BOOKS_ID;
878 4
    }
879
}
880
881
class PageQueryResult extends Page
882
{
883
    const SCOPE_TAG = "tag";
884
    const SCOPE_RATING = "rating";
885
    const SCOPE_SERIES = "series";
886
    const SCOPE_AUTHOR = "author";
887
    const SCOPE_BOOK = "book";
888
    const SCOPE_PUBLISHER = "publisher";
889
890 24
    private function useTypeahead () {
891 24
        return !is_null (getURLParam ("search"));
892
    }
893
894 29
    private function searchByScope ($scope, $limit = FALSE) {
895 29
        $n = $this->n;
896 29
        $numberPerPage = NULL;
897 29
        $queryNormedAndUp = $this->query;
898 29
        if (useNormAndUp ()) {
899 7
            $queryNormedAndUp = normAndUp ($this->query);
900 7
        }
901 29
        if ($limit) {
902 22
            $n = 1;
903 22
            $numberPerPage = 5;
904 22
        }
905
        switch ($scope) {
906 29
            case self::SCOPE_BOOK :
907 23
                $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, $numberPerPage);
908 23
                break;
909 28
            case self::SCOPE_AUTHOR :
910 23
                $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp);
911 23
                break;
912 25
            case self::SCOPE_SERIES :
913 22
                $array = Serie::getAllSeriesByQuery ($queryNormedAndUp);
914 22
                break;
915 24
            case self::SCOPE_TAG :
916 23
                $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage);
917 23
                break;
918 23
            case self::SCOPE_PUBLISHER :
919 23
                $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp);
920 23
                break;
921
            default:
922
                $array = Book::getBooksByQuery (
923
                    array ("all" => "%" . $queryNormedAndUp . "%"), $n);
924
        }
925
926 29
        return $array;
927
    }
928
929 22
    public function doSearchByCategory () {
930 22
        $database = GetUrlParam (DB);
931 22
        $out = array ();
932 22
        $pagequery = Base::PAGE_OPENSEARCH_QUERY;
933 22
        $dbArray = array ("");
934 22
        $d = $database;
935 22
        $query = $this->query;
936
        // Special case when no databases were chosen, we search on all databases
937 22
        if (Base::noDatabaseSelected ()) {
938 1
            $dbArray = Base::getDbNameList ();
939 1
            $d = 0;
940 1
        }
941 22
        foreach ($dbArray as $key) {
942 22
            if (Base::noDatabaseSelected ()) {
943 1
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$d}",
944 1
                                        " ", "text",
945 1
                                        array ( new LinkNavigation ("?" . DB . "={$d}")), "tt-header"));
946 1
                Base::getDb ($d);
947 1
            }
948 22
            foreach (array (PageQueryResult::SCOPE_BOOK,
949 22
                            PageQueryResult::SCOPE_AUTHOR,
950 22
                            PageQueryResult::SCOPE_SERIES,
951 22
                            PageQueryResult::SCOPE_TAG,
952 22
                            PageQueryResult::SCOPE_PUBLISHER) as $key) {
953 22
                if (in_array($key, getCurrentOption ('ignored_categories'))) {
954 3
                    continue;
955
                }
956 22
                $array = $this->searchByScope ($key, TRUE);
957
958 22
                $i = 0;
959 22
                if (count ($array) == 2 && is_array ($array [0])) {
960 22
                    $total = $array [1];
961 22
                    $array = $array [0];
962 22
                } else {
963 22
                    $total = count($array);
964
                }
965 22
                if ($total > 0) {
966
                    // Comment to help the perl i18n script
967
                    // str_format (localize("bookword", count($array))
968
                    // str_format (localize("authorword", count($array))
969
                    // str_format (localize("seriesword", count($array))
970
                    // str_format (localize("tagword", count($array))
971
                    // str_format (localize("publisherword", count($array))
972 21
                    array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}",
973 21
                                        str_format (localize("{$key}word", $total), $total), "text",
974 21
                                        array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&scope={$key}")),
975 21
                                        Base::noDatabaseSelected () ? "" : "tt-header", $total));
976 21
                }
977 22
                if (!Base::noDatabaseSelected () && $this->useTypeahead ()) {
978 6
                    foreach ($array as $entry) {
979 6
                        array_push ($this->entryArray, $entry);
980 6
                        $i++;
981 6
                        if ($i > 4) { break; };
982 6
                    }
983 6
                }
984 22
            }
985 22
            $d++;
986 22
            if (Base::noDatabaseSelected ()) {
987 1
                Base::clearDb ();
988 1
            }
989 22
        }
990 22
        return $out;
991
    }
992
993 31
    public function InitializeContent ()
994
    {
995 31
        $scope = getURLParam ("scope");
996 31
        if (empty ($scope)) {
997 24
            $this->title = str_format (localize ("search.result"), $this->query);
998 24
        } else {
999
            // Comment to help the perl i18n script
1000
            // str_format (localize ("search.result.author"), $this->query)
1001
            // str_format (localize ("search.result.tag"), $this->query)
1002
            // str_format (localize ("search.result.series"), $this->query)
1003
            // str_format (localize ("search.result.book"), $this->query)
1004
            // str_format (localize ("search.result.publisher"), $this->query)
1005 7
            $this->title = str_format (localize ("search.result.{$scope}"), $this->query);
1006
        }
1007
1008 31
        $crit = "%" . $this->query . "%";
1009
1010
        // Special case when we are doing a search and no database is selected
1011 31
        if (Base::noDatabaseSelected () && !$this->useTypeahead ()) {
1012 2
            $i = 0;
1013 2
            foreach (Base::getDbNameList () as $key) {
1014 2
                Base::clearDb ();
1015 2
                list ($array, $totalNumber) = Book::getBooksByQuery (array ("all" => $crit), 1, $i, 1);
0 ignored issues
show
The assignment to $array is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1016 2
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}",
1017 2
                                        str_format (localize ("bookword", $totalNumber), $totalNumber), "text",
1018 2
                                        array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber));
1019 2
                $i++;
1020 2
            }
1021 2
            return;
1022
        }
1023 29
        if (empty ($scope)) {
1024 22
            $this->doSearchByCategory ();
1025 22
            return;
1026
        }
1027
1028 7
        $array = $this->searchByScope ($scope);
1029 7
        if (count ($array) == 2 && is_array ($array [0])) {
1030 2
            list ($this->entryArray, $this->totalNumber) = $array;
1031 2
        } else {
1032 5
            $this->entryArray = $array;
1033
        }
1034 7
    }
1035
}
1036
1037
class PageBookDetail extends Page
1038
{
1039 1
    public function InitializeContent ()
1040
    {
1041 1
        $this->book = Book::getBookById ($this->idGet);
1042 1
        $this->title = $this->book->title;
1043 1
    }
1044
}
1045
1046
class PageAbout extends Page
1047
{
1048
    public function InitializeContent ()
1049
    {
1050
        $this->title = localize ("about.title");
1051
    }
1052
}
1053
1054
class PageCustomize extends Page
1055
{
1056
    private function isChecked ($key, $testedValue = 1) {
1057
        $value = getCurrentOption ($key);
1058
        if (is_array ($value)) {
1059
            if (in_array ($testedValue, $value)) {
1060
                return "checked='checked'";
1061
            }
1062
        } else {
1063
            if ($value == $testedValue) {
1064
                return "checked='checked'";
1065
            }
1066
        }
1067
        return "";
1068
    }
1069
1070
    private function isSelected ($key, $value) {
1071
        if (getCurrentOption ($key) == $value) {
1072
            return "selected='selected'";
1073
        }
1074
        return "";
1075
    }
1076
1077
    private function getStyleList () {
1078
        $result = array ();
1079
        foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) {
1080
            if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) {
1081
                array_push ($result, $m [1]);
1082
            }
1083
        }
1084
        return $result;
1085
    }
1086
1087
    public function InitializeContent ()
1088
    {
1089
        $this->title = localize ("customize.title");
1090
        $this->entryArray = array ();
1091
1092
        $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR,
1093
                                   PageQueryResult::SCOPE_TAG,
1094
                                   PageQueryResult::SCOPE_SERIES,
1095
                                   PageQueryResult::SCOPE_PUBLISHER,
1096
                                   PageQueryResult::SCOPE_RATING,
1097
                                   "language");
1098
1099
        $content = "";
1100
        array_push ($this->entryArray, new Entry ("Template", "",
1101
                                        "<span style='cursor: pointer;' onclick='$.cookie(\"template\", \"bootstrap\", { expires: 365 });window.location=$(\".headleft\").attr(\"href\");'>Click to switch to Bootstrap</span>", "text",
1102
                                        array ()));
1103
        if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) {
1104
            $content .= '<select id="style" onchange="updateCookie (this);">';
1105
            foreach ($this-> getStyleList () as $filename) {
1106
                $content .= "<option value='{$filename}' " . $this->isSelected ("style", $filename) . ">{$filename}</option>";
1107
            }
1108
            $content .= '</select>';
1109
        } else {
1110
            foreach ($this-> getStyleList () as $filename) {
1111
                $content .= "<input type='radio' onchange='updateCookieFromCheckbox (this);' id='style-{$filename}' name='style' value='{$filename}' " . $this->isChecked ("style", $filename) . " /><label for='style-{$filename}'> {$filename} </label>";
1112
            }
1113
        }
1114
        array_push ($this->entryArray, new Entry (localize ("customize.style"), "",
1115
                                        $content, "text",
1116
                                        array ()));
1117
        if (!useServerSideRendering ()) {
1118
            $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="use_fancyapps" ' . $this->isChecked ("use_fancyapps") . ' />';
1119
            array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "",
1120
                                            $content, "text",
1121
                                            array ()));
1122
        }
1123
        $content = '<input type="number" onchange="updateCookie (this);" id="max_item_per_page" value="' . getCurrentOption ("max_item_per_page") . '" min="-1" max="1200" pattern="^[-+]?[0-9]+$" />';
1124
        array_push ($this->entryArray, new Entry (localize ("customize.paging"), "",
1125
                                        $content, "text",
1126
                                        array ()));
1127
        $content = '<input type="text" onchange="updateCookie (this);" id="email" value="' . getCurrentOption ("email") . '" />';
1128
        array_push ($this->entryArray, new Entry (localize ("customize.email"), "",
1129
                                        $content, "text",
1130
                                        array ()));
1131
        $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="html_tag_filter" ' . $this->isChecked ("html_tag_filter") . ' />';
1132
        array_push ($this->entryArray, new Entry (localize ("customize.filter"), "",
1133
                                        $content, "text",
1134
                                        array ()));
1135
        $content = "";
1136
        foreach ($ignoredBaseArray as $key) {
1137
            $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s");
1138
            $content .=  '<input type="checkbox" name="ignored_categories[]" onchange="updateCookieFromCheckboxGroup (this);" id="ignored_categories_' . $key . '" ' . $this->isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . '</input> ';
1139
        }
1140
1141
        array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "",
1142
                                        $content, "text",
1143
                                        array ()));
1144
    }
1145
}
1146
1147
1148
abstract class Base
1149
{
1150
    const PAGE_INDEX = "index";
1151
    const PAGE_ALL_AUTHORS = "1";
1152
    const PAGE_AUTHORS_FIRST_LETTER = "2";
1153
    const PAGE_AUTHOR_DETAIL = "3";
1154
    const PAGE_ALL_BOOKS = "4";
1155
    const PAGE_ALL_BOOKS_LETTER = "5";
1156
    const PAGE_ALL_SERIES = "6";
1157
    const PAGE_SERIE_DETAIL = "7";
1158
    const PAGE_OPENSEARCH = "8";
1159
    const PAGE_OPENSEARCH_QUERY = "9";
1160
    const PAGE_ALL_RECENT_BOOKS = "10";
1161
    const PAGE_ALL_TAGS = "11";
1162
    const PAGE_TAG_DETAIL = "12";
1163
    const PAGE_BOOK_DETAIL = "13";
1164
    const PAGE_ALL_CUSTOMS = "14";
1165
    const PAGE_CUSTOM_DETAIL = "15";
1166
    const PAGE_ABOUT = "16";
1167
    const PAGE_ALL_LANGUAGES = "17";
1168
    const PAGE_LANGUAGE_DETAIL = "18";
1169
    const PAGE_CUSTOMIZE = "19";
1170
    const PAGE_ALL_PUBLISHERS = "20";
1171
    const PAGE_PUBLISHER_DETAIL = "21";
1172
    const PAGE_ALL_RATINGS = "22";
1173
    const PAGE_RATING_DETAIL = "23";
1174
1175
    const COMPATIBILITY_XML_ALDIKO = "aldiko";
1176
    
1177
    const SQL_SETTING = 'SELECT val FROM preferences WHERE key = "{0}"';
1178
1179
    private static $db = NULL;
1180
1181 108
    public static function isMultipleDatabaseEnabled () {
1182 108
        global $config;
1183 108
        return is_array ($config['calibre_directory']);
1184
    }
1185
1186 46
    public static function useAbsolutePath () {
1187 46
        global $config;
1188 46
        $path = self::getDbDirectory();
1189 46
        return preg_match ('/^\//', $path) || // Linux /
1190 46
               preg_match ('/^\w\:/', $path); // Windows X:
1191
    }
1192
1193 45
    public static function noDatabaseSelected () {
1194 45
        return (self::isMultipleDatabaseEnabled () || VirtualLib::isVLEnabled())
1195 45
        	&& is_null (GetUrlParam (DB));
1196
    }
1197
1198 4
    public static function getDbList () {
1199 4
        global $config;
1200 4
        if (self::isMultipleDatabaseEnabled ()) {
1201 4
            return $config['calibre_directory'];
1202
        } else {
1203 1
            return array ("" => $config['calibre_directory']);
1204
        }
1205
    }
1206
1207 5
    public static function getDbNameList () {
1208 5
        global $config;
1209 5
        if (self::isMultipleDatabaseEnabled ()) {
1210 5
            return array_keys ($config['calibre_directory']);
1211
        } else {
1212
            return array ("");
1213
        }
1214
    }
1215
1216 1
    public static function getDbName ($database = NULL) {
1217 1
        global $config;
1218 1
        if (self::isMultipleDatabaseEnabled ()) {
1219 1
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1220 1
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1221
                return self::error ($database);
1222
            }
1223 1
            $array = array_keys ($config['calibre_directory']);
1224 1
            return  $array[$database];
1225
        }
1226
        return "";
1227
    }
1228
1229 90
    public static function getDbDirectory ($database = NULL) {
1230 90
        global $config;
1231 90
        if (self::isMultipleDatabaseEnabled ()) {
1232 9
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1233 9
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1234
                return self::error ($database);
1235
            }
1236 9
            $array = array_values ($config['calibre_directory']);
1237 9
            return  $array[$database];
1238
        }
1239 81
        return $config['calibre_directory'];
1240
    }
1241
1242
1243 61
    public static function getDbFileName ($database = NULL) {
1244 61
        return self::getDbDirectory ($database) .'metadata.db';
1245
    }
1246
1247 2
    private static function error ($database) {
1248 2
        if (php_sapi_name() != "cli") {
1249
            header("location: checkconfig.php?err=1");
1250
        }
1251 2
        throw new Exception("Database <{$database}> not found.");
1252
    }
1253
1254 126
    public static function getDb ($database = NULL) {
1255 126
        if (is_null (self::$db)) {
1256
            try {
1257 61
                if (is_readable (self::getDbFileName ($database))) {
1258 60
                    self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
1259 60
                    if (useNormAndUp ()) {
1260 7
                        self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1);
1261 7
                    }
1262 60
                } else {
1263 2
                    self::error ($database);
1264
                }
1265 61
            } catch (Exception $e) {
1266 2
                self::error ($database);
1267
            }
1268 60
        }
1269 125
        return self::$db;
1270
    }
1271
1272 4
    public static function checkDatabaseAvailability () {
1273 4
        if (self::noDatabaseSelected ()) {
1274 3
            for ($i = 0; $i < count (self::getDbList ()); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1275 3
                self::getDb ($i);
1276 2
                self::clearDb ();
1277 2
            }
1278 1
        } else {
1279 1
            self::getDb ();
1280
        }
1281 2
        return true;
1282
    }
1283
1284 58
    public static function clearDb () {
1285 58
        self::$db = NULL;
1286 58
    }
1287
1288 13
    public static function executeQuerySingle ($query, $database = NULL) {
1289 13
        return self::getDb ($database)->query($query)->fetchColumn();
1290
    }
1291
1292 8
    public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL) {
1293 8
        if (!$numberOfString) {
1294 7
            $numberOfString = $table . ".alphabetical";
1295 7
        }
1296 8
        $count = self::executeQuerySingle ('select count(*) from ' . $table);
1297 8
        if ($count == 0) return NULL;
1298 8
        $entry = new Entry (localize($table . ".title"), $id,
1299 8
            str_format (localize($numberOfString, $count), $count), "text",
1300 8
            array ( new LinkNavigation ("?page=".$pageId)), "", $count);
1301 8
        return $entry;
1302
    }
1303
1304 35
    public static function getEntryArrayWithBookNumber ($query, $columns, $params, $category) {
1305 35
        list (, $result) = self::executeQuery ($query, $columns, "", $params, -1);
1306 35
        $entryArray = array();
1307 35
        while ($post = $result->fetchObject ())
1308
        {
1309 25
            $instance = new $category ($post);
1310 25
            if (property_exists($post, "sort")) {
1311 17
                $title = $post->sort;
1312 17
            } else {
1313 8
                $title = $post->name;
1314
            }
1315 25
            array_push ($entryArray, new Entry ($title, $instance->getEntryId (),
1316 25
                str_format (localize("bookword", $post->count), $post->count), "text",
1317 25
                array ( new LinkNavigation ($instance->getUri ())), "", $post->count));
1318 25
        }
1319 35
        return $entryArray;
1320
    }
1321
1322 73
    public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL) {
1323 73
        $totalResult = -1;
1324
1325 73
        if (useNormAndUp ()) {
1326 7
            $query = preg_replace("/upper/", "normAndUp", $query);
1327 7
            $columns = preg_replace("/upper/", "normAndUp", $columns);
1328 7
        }
1329
1330 73
        if (is_null ($numberPerPage)) {
1331 71
            $numberPerPage = getCurrentOption ("max_item_per_page");
1332 71
        }
1333
1334 73
        if ($numberPerPage != -1 && $n != -1)
1335 73
        {
1336
            // First check total number of results
1337 28
            $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
1338 28
            $result->execute ($params);
1339 28
            $totalResult = $result->fetchColumn ();
1340
1341
            // Next modify the query and params
1342 28
            $query .= " limit ?, ?";
1343 28
            array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage);
1344 28
        }
1345
1346 73
        $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
1347 73
        $result->execute ($params);
1348 73
        return array ($totalResult, $result);
1349
    }
1350
1351
    /**
1352
     * Gets a calibre setting from the database.
1353
     * 
1354
     * @param string $name Name of the property
1355
     * @param int $database Database to query from
1356
     * @return string Value of the property
1357
     */
1358
    public static function getCalibreSetting($name, $database = NULL) {
1359
    	$query = str_format(self::SQL_SETTING, $name);
1360
    	return self::executeQuerySingle($query, $database);
1361
    }
1362
}
1363