Completed
Push — master ( 267988...a9e5cc )
by Sébastien
13: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
/** @var array $config */
10
11
define ("VERSION", "1.0.0RC4");
12
define ("DB", "db");
13
date_default_timezone_set($config['default_timezone']);
14
15 3
16 3
function useServerSideRendering () {
17
    global $config;
18
    return preg_match("/" . $config['cops_server_side_render'] . "/", $_SERVER['HTTP_USER_AGENT']);
19
}
20
21 2
function serverSideRender ($data) {
22 2
    // 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
    $bookdetail = file_get_contents('templates/' . $theme . '/bookdetail.html');
28
    $page = file_get_contents('templates/' . $theme . '/page.html');
29 2
30 2
    // 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
                                              "footer" => $footer,
35
                                              "main" => $main));
36 2
    // If there is a syntax error in the function created
37
    // $dot will be equal to FALSE
38
    if (!$dot) {
39
        return FALSE;
40 2
    }
41
    // Execute the template
42
    if (!empty ($data)) {
43
        return $dot ($data);
44 2
    }
45
46
    return NULL;
47
}
48 18
49 16
function getQueryString () {
50
    if ( isset($_SERVER['QUERY_STRING']) ) {
51 2
        return $_SERVER['QUERY_STRING'];
52
    }
53
    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 101
63 24
function getURLParam ($name, $default = NULL) {
64
    if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") {
65 101
        return $_GET[$name];
66
    }
67
    return $default;
68
}
69 87
70 87
function getCurrentOption ($option) {
71 2
    global $config;
72
    if (isset($_COOKIE[$option])) {
73
        if (isset($config ["cops_" . $option]) && is_array ($config ["cops_" . $option])) {
74 2
            return explode (",", $_COOKIE[$option]);
75
        } else {
76
            return $_COOKIE[$option];
77 85
        }
78 85
    }
79
    if (isset($config ["cops_" . $option])) {
80
        return $config ["cops_" . $option];
81
    }
82
83
    return "";
84
}
85 2
86
function getCurrentCss () {
87
    return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css";
88
}
89 4
90
function getCurrentTemplate () {
91
    return getCurrentOption ("template");
92
}
93 51
94
function getUrlWithVersion ($url) {
95
    return $url . "?v=" . VERSION;
96
}
97 35
98
function xml2xhtml($xml) {
99
    return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', create_function('$m', '
100 35
        $xhtml_tags = array("br", "hr", "input", "frame", "img", "area", "link", "col", "base", "basefont", "param");
101
        return in_array($m[1], $xhtml_tags) ? "<$m[1]$m[2] />" : "<$m[1]$m[2]></$m[1]>";
102
    '), $xml);
103
}
104
105
function display_xml_error($error)
106
{
107
    $return = "";
108
    $return .= str_repeat('-', $error->column) . "^\n";
109
110
    switch ($error->level) {
111
        case LIBXML_ERR_WARNING:
112
            $return .= "Warning $error->code: ";
113
            break;
114
         case LIBXML_ERR_ERROR:
115
            $return .= "Error $error->code: ";
116
            break;
117
        case LIBXML_ERR_FATAL:
118
            $return .= "Fatal Error $error->code: ";
119
            break;
120
    }
121
122
    $return .= trim($error->message) .
123
               "\n  Line: $error->line" .
124
               "\n  Column: $error->column";
125
126
    if ($error->file) {
127
        $return .= "\n  File: $error->file";
128
    }
129
130
    return "$return\n\n--------------------------------------------\n\n";
131
}
132
133 35
function are_libxml_errors_ok ()
134
{
135 35
    $errors = libxml_get_errors();
136
137 35
    foreach ($errors as $error) {
138 35
        if ($error->code == 801) return false;
139
    }
140
    return true;
141
}
142 35
143 35
function html2xhtml ($html) {
144
    $doc = new DOMDocument();
145 35
    libxml_use_internal_errors(true);
146 35
147 35
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
148 35
                        $html  . '</body></html>'); // Load the HTML
149 35
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
150 35
    $output = xml2xhtml($output);
151 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)) {
152
        $output = $matches [1]; // Remove <html><body>
153
    }
154
    /*
155
    // In case of error with summary, use it to debug
156
    $errors = libxml_get_errors();
157
158
    foreach ($errors as $error) {
159
        $output .= display_xml_error($error);
160
    }
161 35
    */
162
163 35
    if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
164 35
165
    libxml_use_internal_errors(false);
166
    return $output;
167
}
168
169
/**
170
 * This method is a direct copy-paste from
171
 * http://tmont.com/blargh/2010/1/string-format-in-php
172 94
 */
173 94
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...
174
    $args = func_get_args();
175 94
    $format = array_shift($args);
176 94
177 94
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
178 94
    $offset = 0;
179 94
    foreach ($matches[1] as $data) {
180 94
        $i = $data[0];
181 94
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
182
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
183 94
    }
184
185
    return $format;
186
}
187
188
/**
189
 * Get all accepted languages from the browser and put them in a sorted array
190
 * languages id are normalized : fr-fr -> fr_FR
191
 * @return array of languages
192 16
 */
193
function getAcceptLanguages() {
194 16
    $langs = array();
195
196 16
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
197 16
        // break up string into pieces (languages and q factors)
198
        $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
199 3
        if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) {
200 3
            // Special fix for IE11 which send fr-FR and nothing else
201 16
            $accept = $accept . "," . $matches[1] . ";q=0.8";
202
        }
203 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);
204 16
205 16
        if (count($lang_parse[1])) {
206
            $langs = array();
207 16
            foreach ($lang_parse[1] as $lang) {
208 11
                // Format the language code (not standard among browsers)
209 11
                if (strlen($lang) == 5) {
210 11
                    $lang = str_replace("-", "_", $lang);
211 11
                    $splitted = preg_split("/_/", $lang);
212 16
                    $lang = $splitted[0] . "_" . strtoupper($splitted[1]);
213 16
                }
214
                array_push($langs, $lang);
215 16
            }
216
            // create a list like "en" => 0.8
217
            $langs = array_combine($langs, $lang_parse[4]);
218 16
219 16
            // set default to 1 for any without q factor
220 16
            foreach ($langs as $lang => $val) {
221
                if ($val === '') $langs[$lang] = 1;
222
            }
223 16
224 16
            // sort list based on value
225 16
            arsort($langs, SORT_NUMERIC);
226
        }
227 16
    }
228
229
    return $langs;
230
}
231
232
/**
233
 * Find the best translation file possible based on the accepted languages
234
 * @return array of language and language file
235 17
 */
236 17
function getLangAndTranslationFile() {
237 17
    global $config;
238 17
    $langs = array();
239
    $lang = "en";
240
    if (!empty($config['cops_language'])) {
241 17
        $lang = $config['cops_language'];
242 16
    }
243 16
    elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
244
        $langs = getAcceptLanguages();
245 17
    }
246 17
    //echo var_dump($langs);
247 16
    $lang_file = NULL;
248 16
    foreach ($langs as $language => $val) {
249 16
        $temp_file = dirname(__FILE__). '/lang/Localization_' . $language . '.json';
250 16
        if (file_exists($temp_file)) {
251 16
            $lang = $language;
252
            $lang_file = $temp_file;
253 17
            break;
254 17
        }
255 3
    }
256 3
    if (empty ($lang_file)) {
257 17
        $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
258
    }
259
    return array($lang, $lang_file);
260
}
261
262
/**
263
 * This method is based on this page
264
 * http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/
265 114
 */
266 114
function localize($phrase, $count=-1, $reset=false) {
267 114
    global $config;
268 114
    if ($count == 0)
269 114
        $phrase .= ".none";
270 114
    if ($count == 1)
271 114
        $phrase .= ".one";
272
    if ($count > 1)
273
        $phrase .= ".many";
274 114
275 114
    /* Static keyword is used to ensure the file is loaded only once */
276 16
    static $translations = NULL;
277 16
    if ($reset) {
278
        $translations = NULL;
279 114
    }
280 17
    /* If no instance of $translations has occured load the language file */
281 17
    if (is_null($translations)) {
282 17
        $lang_file_en = NULL;
283 1
        list ($lang, $lang_file) = getLangAndTranslationFile();
284 1
        if ($lang != "en") {
285
            $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
286 17
        }
287
288 17
        $lang_file_content = file_get_contents($lang_file);
289
        /* Load the language file as a JSON object and transform it into an associative array */
290
        $translations = json_decode($lang_file_content, true);
291 17
292 17
        /* Clean the array of all unfinished translations */
293
        foreach (array_keys ($translations) as $key) {
294
            if (preg_match ("/^##TODO##/", $key)) {
295 17
                unset ($translations [$key]);
296
            }
297 17
        }
298 1
        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...
299 1
        {
300 1
            $lang_file_content = file_get_contents($lang_file_en);
301 1
            $translations_en = json_decode($lang_file_content, true);
302 17
            $translations = array_merge ($translations_en, $translations);
303 114
        }
304 114
    }
305
    if (array_key_exists ($phrase, $translations)) {
306 1
        return $translations[$phrase];
307
    }
308
    return $phrase;
309
}
310 58
311 48
function addURLParameter($urlParams, $paramName, $paramValue) {
312 48
    if (empty ($urlParams)) {
313 58
        $urlParams = "";
314 58
    }
315 15
    $start = "";
316 15
    if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
317 15
        $start = "?";
318 58
        $urlParams = $matches[1];
319 58
    }
320 58
    $params = array();
321
    parse_str($urlParams, $params);
322
    if (empty ($paramValue) && $paramValue != 0) {
323 58
        unset ($params[$paramName]);
324
    } else {
325 58
        $params[$paramName] = $paramValue;
326
    }
327
    return $start . http_build_query($params);
328
}
329 113
330 113
function useNormAndUp () {
331
    global $config;
332
    return $config ['cops_normalized_search'] == "1";
333
}
334 8
335 8
function normalizeUtf8String( $s) {
336
    include_once 'transliteration.php';
337
    return _transliteration_process($s);
338
}
339 7
340
function normAndUp ($s) {
341
    return mb_strtoupper (normalizeUtf8String($s), 'UTF-8');
342
}
343
344
class Link
345
{
346
    const OPDS_THUMBNAIL_TYPE = "http://opds-spec.org/image/thumbnail";
347
    const OPDS_IMAGE_TYPE = "http://opds-spec.org/image";
348
    const OPDS_ACQUISITION_TYPE = "http://opds-spec.org/acquisition";
349
    const OPDS_NAVIGATION_TYPE = "application/atom+xml;profile=opds-catalog;kind=navigation";
350
    const OPDS_PAGING_TYPE = "application/atom+xml;profile=opds-catalog;kind=acquisition";
351
352
    public $href;
353
    public $type;
354
    public $rel;
355
    public $title;
356
    public $facetGroup;
357 96
    public $activeFacet;
358 96
359 96
    public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
360 96
        $this->href = $phref;
361 96
        $this->type = $ptype;
362 96
        $this->rel = $prel;
363 96
        $this->title = $ptitle;
364 96
        $this->facetGroup = $pfacetGroup;
365
        $this->activeFacet = $pactiveFacet;
366 10
    }
367 10
368
    public function hrefXhtml () {
369
        return $this->href;
370 95
    }
371 95
372 95
    public function getScriptName() {
373
        $parts = explode('/', $_SERVER["SCRIPT_NAME"]);
374
        return $parts[count($parts) - 1];
375
    }
376
}
377
378 95
class LinkNavigation extends Link
379 95
{
380 95
    public function __construct($phref, $prel = NULL, $ptitle = NULL) {
381 95
        parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
382 95
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
383
        if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
384
        if (preg_match ("/(bookdetail|getJSON).php/", parent::getScriptName())) {
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getScriptName() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getScriptName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
385 95
            $this->href = "index.php" . $this->href;
386
        } else {
387 95
            $this->href = parent::getScriptName() . $this->href;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getScriptName() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getScriptName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
388
        }
389
    }
390
}
391
392 1
class LinkFacet extends Link
393 1
{
394 1
    public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
395 1
        parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet);
396 1
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
397
        $this->href = parent::getScriptName() . $this->href;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getScriptName() instead of __construct()). Are you sure this is correct? If so, you might want to change this to $this->getScriptName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
398
    }
399
}
400
401
class Entry
402
{
403
    public $title;
404
    public $id;
405
    public $content;
406
    public $numberOfElement;
407
    public $contentType;
408
    public $linkArray;
409
    public $localUpdated;
410
    public $className;
411
    private static $updated = NULL;
412
413
    public static $icons = array(
414
        Author::ALL_AUTHORS_ID           => 'images/author.png',
415
        Serie::ALL_SERIES_ID             => 'images/serie.png',
416
        Book::ALL_RECENT_BOOKS_ID        => 'images/recent.png',
417
        Tag::ALL_TAGS_ID                 => 'images/tag.png',
418
        Language::ALL_LANGUAGES_ID       => 'images/language.png',
419
        CustomColumnType::ALL_CUSTOMS_ID => 'images/custom.png',
420
        Rating::ALL_RATING_ID            => 'images/rating.png',
421
        "cops:books$"                    => 'images/allbook.png',
422
        "cops:books:letter"              => 'images/allbook.png',
423
        Publisher::ALL_PUBLISHERS_ID     => 'images/publisher.png'
424
    );
425
426
    public function getUpdatedTime () {
427
        if (!is_null ($this->localUpdated)) {
428
            return date (DATE_ATOM, $this->localUpdated);
429
        }
430
        if (is_null (self::$updated)) {
431
            self::$updated = time();
432
        }
433
        return date (DATE_ATOM, self::$updated);
434 7
    }
435 7
436 7
    public function getNavLink () {
437
        foreach ($this->linkArray as $link) {
438 7
            /* @var $link LinkNavigation */
439
440
            if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
441
442
            return $link->hrefXhtml ();
443 89
        }
444 89
        return "#";
445 89
    }
446 89
447 89
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) {
448 89
        global $config;
449 89
        $this->title = $ptitle;
450 89
        $this->id = $pid;
451 89
        $this->content = $pcontent;
452
        $this->contentType = $pcontentType;
453 89
        $this->linkArray = $plinkArray;
454 89
        $this->className = $pclass;
455 89
        $this->numberOfElement = $pcount;
456
457 89
        if ($config['cops_show_icons'] == 1)
458 51
        {
459 51
            foreach (self::$icons as $reg => $image)
460
            {
461 89
                if (preg_match ("/" . $reg . "/", $pid)) {
462 89
                    array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE));
463
                    break;
464 89
                }
465 89
            }
466
        }
467
468
        if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $this->id);
469
    }
470
}
471
472 39
class EntryBook extends Entry
473 39
{
474 39
    public $book;
475 39
476 39
    /**
477
     * EntryBook constructor.
478
     * @param string $ptitle
479
     * @param integer $pid
480
     * @param string $pcontent
481
     * @param string $pcontentType
482
     * @param array $plinkArray
483
     * @param Book $pbook
484
     */
485
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) {
486
        parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray);
487
        $this->book = $pbook;
488
        $this->localUpdated = $pbook->timestamp;
489
    }
490
491
    public function getCoverThumbnail () {
492
        foreach ($this->linkArray as $link) {
493
            /* @var $link LinkNavigation */
494
495
            if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
496
                return $link->hrefXhtml ();
497
        }
498
        return null;
499
    }
500
501
    public function getCover () {
502
        foreach ($this->linkArray as $link) {
503
            /* @var $link LinkNavigation */
504
505
            if ($link->rel == Link::OPDS_IMAGE_TYPE)
506
                return $link->hrefXhtml ();
507
        }
508
        return null;
509
    }
510
}
511 81
512
class Page
513
{
514 81
    public $title;
515 3
    public $subtitle = "";
516 78
    public $authorName = "";
517 1
    public $authorUri = "";
518 77
    public $authorEmail = "";
519 7
    public $idPage;
520 70
    public $idGet;
521 2
    public $query;
522 68
    public $favicon;
523 1
    public $n;
524 67
    public $book;
525 2
    public $totalNumber = -1;
526 65
527 1
    /* @var Entry[] */
528 64
    public $entryArray = array();
529 3
530 61
    public static function getPage ($pageId, $id, $query, $n)
531 3
    {
532 58
        switch ($pageId) {
533 1
            case Base::PAGE_ALL_AUTHORS :
534 57
                return new PageAllAuthors ($id, $query, $n);
535 1
            case Base::PAGE_AUTHORS_FIRST_LETTER :
536 56
                return new PageAllAuthorsLetter ($id, $query, $n);
537 2
            case Base::PAGE_AUTHOR_DETAIL :
538 54
                return new PageAuthorDetail ($id, $query, $n);
539 3
            case Base::PAGE_ALL_TAGS :
540 51
                return new PageAllTags ($id, $query, $n);
541 1
            case Base::PAGE_TAG_DETAIL :
542 50
                return new PageTagDetail ($id, $query, $n);
543 4
            case Base::PAGE_ALL_LANGUAGES :
544 46
                return new PageAllLanguages ($id, $query, $n);
545 1
            case Base::PAGE_LANGUAGE_DETAIL :
546 45
                return new PageLanguageDetail ($id, $query, $n);
547 31
            case Base::PAGE_ALL_CUSTOMS :
548 14
                return new PageAllCustoms ($id, $query, $n);
549 1
            case Base::PAGE_CUSTOM_DETAIL :
550 13
                return new PageCustomDetail ($id, $query, $n);
551 2
            case Base::PAGE_ALL_RATINGS :
552 11
                return new PageAllRating ($id, $query, $n);
553 1
            case Base::PAGE_RATING_DETAIL :
554 10
                return new PageRatingDetail ($id, $query, $n);
555
            case Base::PAGE_ALL_SERIES :
556 10
                return new PageAllSeries ($id, $query, $n);
557
            case Base::PAGE_ALL_BOOKS :
558 10
                return new PageAllBooks ($id, $query, $n);
559 10
            case Base::PAGE_ALL_BOOKS_LETTER:
560 10
                return new PageAllBooksLetter ($id, $query, $n);
561 10
            case Base::PAGE_ALL_RECENT_BOOKS :
562 10
                return new PageRecentBooks ($id, $query, $n);
563
            case Base::PAGE_SERIE_DETAIL :
564
                return new PageSerieDetail ($id, $query, $n);
565 81
            case Base::PAGE_OPENSEARCH_QUERY :
566 81
                return new PageQueryResult ($id, $query, $n);
567
            case Base::PAGE_BOOK_DETAIL :
568 81
                return new PageBookDetail ($id, $query, $n);
569 81
            case Base::PAGE_ALL_PUBLISHERS:
570 81
                return new PageAllPublishers ($id, $query, $n);
571 81
            case Base::PAGE_PUBLISHER_DETAIL :
572 81
                return new PagePublisherDetail ($id, $query, $n);
573 81
            case Base::PAGE_ABOUT :
574 81
                return new PageAbout ($id, $query, $n);
575 81
            case Base::PAGE_CUSTOMIZE :
576
                return new PageCustomize ($id, $query, $n);
577 10
            default:
578
                $page = new Page ($id, $query, $n);
579 10
                $page->idPage = "cops:catalog";
580 10
                return $page;
581 10
        }
582 10
    }
583 2
584 2
    public function __construct($pid, $pquery, $pn) {
585 2
        global $config;
586 2
587 2
        $this->idGet = $pid;
588 2
        $this->query = $pquery;
589 2
        $this->n = $pn;
590 2
        $this->favicon = $config['cops_icon'];
591 2
        $this->authorName = empty($config['cops_author_name']) ? utf8_encode('Sébastien Lucas') : $config['cops_author_name'];
592 2
        $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri'];
593 8
        $this->authorEmail = empty($config['cops_author_email']) ? '[email protected]' : $config['cops_author_email'];
594 7
    }
595 7
596 8
    public function InitializeContent ()
597 7
    {
598 7
        global $config;
599 7
        $this->title = $config['cops_title_default'];
600 8
        $this->subtitle = $config['cops_subtitle_default'];
601 7
        if (Base::noDatabaseSelected ()) {
602 7
            $i = 0;
603 7
            foreach (Base::getDbNameList () as $key) {
604 8
                $nBooks = Book::getBookCount ($i);
605 7
                array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog",
606 7
                                        str_format (localize ("bookword", $nBooks), $nBooks), "text",
607 7
                                        array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks));
608 8
                $i++;
609 8
                Base::clearDb ();
610 8
            }
611 8
        } else {
612 8
            if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) {
613 7
                array_push ($this->entryArray, Author::getCount());
614 7
            }
615 7
            if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) {
616 8
                $series = Serie::getCount();
617 4
                if (!is_null ($series)) array_push ($this->entryArray, $series);
618 4
            }
619 4
            if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) {
620 4
                $publisher = Publisher::getCount();
621 8
                if (!is_null ($publisher)) array_push ($this->entryArray, $publisher);
622 8
            }
623
            if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) {
624 8
                $tags = Tag::getCount();
625
                if (!is_null ($tags)) array_push ($this->entryArray, $tags);
626 10
            }
627
            if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) {
628 17
                $rating = Rating::getCount();
629
                if (!is_null ($rating)) array_push ($this->entryArray, $rating);
630 17
            }
631 17
            if (!in_array ("language", getCurrentOption ('ignored_categories'))) {
632 17
                $languages = Language::getCount();
633
                if (!is_null ($languages)) array_push ($this->entryArray, $languages);
634
            }
635 2
            foreach ($config['cops_calibre_custom_column'] as $lookup) {
636
                $customColumn = CustomColumnType::createByLookup($lookup);
637 2
                if (!is_null ($customColumn) && $customColumn->isSearchable()) {
638 2
                    array_push ($this->entryArray, $customColumn->getCount());
639 1
                }
640
            }
641 1
            $this->entryArray = array_merge ($this->entryArray, Book::getCount());
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->entryArray, \Book::getCount()) of type array is incompatible with the declared type array<integer,object<Entry>> of property $entryArray.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
642
643
            if (Base::isMultipleDatabaseEnabled ()) $this->title =  Base::getDbName ();
644 2
        }
645
    }
646 2
647 2
    public function isPaginated ()
648 1
    {
649
        return (getCurrentOption ("max_item_per_page") != -1 &&
650 2
                $this->totalNumber != -1 &&
651
                $this->totalNumber > getCurrentOption ("max_item_per_page"));
652
    }
653 2
654
    public function getNextLink ()
655 2
    {
656
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
657
        if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) {
658 70
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate"));
659
        }
660 70
        return NULL;
661 68
    }
662 46
663
    public function getPrevLink ()
664
    {
665
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
666
        if ($this->n > 1) {
667
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate"));
668 3
        }
669
        return NULL;
670 3
    }
671 3
672 2
    public function getMaxPage ()
673 2
    {
674
        return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page"));
675 1
    }
676
677 3
    public function containsBook ()
678 3
    {
679
        if (count ($this->entryArray) == 0) return false;
680
        if (get_class ($this->entryArray [0]) == "EntryBook") return true;
681
        return false;
682
    }
683 1
}
684
685 1
class PageAllAuthors extends Page
686 1
{
687 1
    public function InitializeContent ()
688 1
    {
689
        $this->title = localize("authors.title");
690
        if (getCurrentOption ("author_split_first_letter") == 1) {
691
            $this->entryArray = Author::getAllAuthorsByFirstLetter();
692
        }
693 7
        else {
694
            $this->entryArray = Author::getAllAuthors();
695 7
        }
696 7
        $this->idPage = Author::ALL_AUTHORS_ID;
697 7
    }
698 7
}
699 7
700
class PageAllAuthorsLetter extends Page
701
{
702
    public function InitializeContent ()
703
    {
704 2
        $this->idPage = Author::getEntryIdByLetter ($this->idGet);
705
        $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet);
706 2
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet);
707 2
    }
708 2
}
709 2
710
class PageAuthorDetail extends Page
711
{
712
    public function InitializeContent ()
713
    {
714 1
        $author = Author::getAuthorById ($this->idGet);
715
        $this->idPage = $author->getEntryId ();
716 1
        $this->title = $author->name;
717 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n);
718 1
    }
719 1
}
720 1
721
class PageAllPublishers extends Page
722
{
723
    public function InitializeContent ()
724
    {
725 2
        $this->title = localize("publishers.title");
726
        $this->entryArray = Publisher::getAllPublishers();
727 2
        $this->idPage = Publisher::ALL_PUBLISHERS_ID;
728 2
    }
729 2
}
730 2
731
class PagePublisherDetail extends Page
732
{
733
    public function InitializeContent ()
734
    {
735 2
        $publisher = Publisher::getPublisherById ($this->idGet);
736
        $this->title = $publisher->name;
737 2
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n);
738 2
        $this->idPage = $publisher->getEntryId ();
739 2
    }
740 2
}
741
742
class PageAllTags extends Page
743
{
744
    public function InitializeContent ()
745 3
    {
746
        $this->title = localize("tags.title");
747 3
        $this->entryArray = Tag::getAllTags();
748 3
        $this->idPage = Tag::ALL_TAGS_ID;
749 3
    }
750 3
}
751 3
752 3
class PageAllLanguages extends Page
753
{
754
    public function InitializeContent ()
755
    {
756
        $this->title = localize("languages.title");
757 3
        $this->entryArray = Language::getAllLanguages();
758
        $this->idPage = Language::ALL_LANGUAGES_ID;
759 3
    }
760 3
}
761 3
762 3
class PageCustomDetail extends Page
763 3
{
764
    public function InitializeContent ()
765
    {
766
        $customId = getURLParam ("custom", NULL);
767
        $custom = CustomColumn::createCustom ($customId, $this->idGet);
768 1
        $this->idPage = $custom->getEntryId ();
769
        $this->title = $custom->value;
770 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($custom, $this->idGet, $this->n);
771 1
    }
772 1
}
773 1
774 1
class PageAllCustoms extends Page
775
{
776
    public function InitializeContent ()
777
    {
778
        $customId = getURLParam ("custom", NULL);
779 1
        $columnType = CustomColumnType::createByCustomID($customId);
780
        
781 1
        $this->title = $columnType->getTitle();
782 1
        $this->entryArray = $columnType->getAllCustomValues();
783 1
        $this->idPage = $columnType->getAllCustomsId();
784 1
    }
785 1
}
786
787
class PageTagDetail extends Page
788
{
789
    public function InitializeContent ()
790 2
    {
791
        $tag = Tag::getTagById ($this->idGet);
792 2
        $this->idPage = $tag->getEntryId ();
793 2
        $this->title = $tag->name;
794 2
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n);
795 2
    }
796
}
797
798
class PageLanguageDetail extends Page
799
{
800 1
    public function InitializeContent ()
801
    {
802 1
        $language = Language::getLanguageById ($this->idGet);
803 1
        $this->idPage = $language->getEntryId ();
804 1
        $this->title = $language->lang_code;
805 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n);
806 1
    }
807
}
808
809
class PageAllSeries extends Page
810
{
811 1
    public function InitializeContent ()
812
    {
813 1
        $this->title = localize("series.title");
814 1
        $this->entryArray = Serie::getAllSeries();
815 1
        $this->idPage = Serie::ALL_SERIES_ID;
816 1
    }
817
}
818
819
class PageSerieDetail extends Page
820
{
821 1
    public function InitializeContent ()
822
    {
823 1
        $serie = Serie::getSerieById ($this->idGet);
824 1
        $this->title = $serie->name;
825 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n);
826 1
        $this->idPage = $serie->getEntryId ();
827 1
    }
828
}
829
830
class PageAllRating extends Page
831
{
832 3
    public function InitializeContent ()
833
    {
834 3
        $this->title = localize("ratings.title");
835 3
        $this->entryArray = Rating::getAllRatings();
836 2
        $this->idPage = Rating::ALL_RATING_ID;
837 2
    }
838
}
839 1
840
class PageRatingDetail extends Page
841 3
{
842 3
    public function InitializeContent ()
843
    {
844
        $rating = Rating::getRatingById ($this->idGet);
845
        $this->idPage = $rating->getEntryId ();
846
        $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2);
847 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n);
848
    }
849 1
}
850 1
851
class PageAllBooks extends Page
852 1
{
853 1
    public function InitializeContent ()
854 1
    {
855
        $this->title = localize ("allbooks.title");
856 1
        if (getCurrentOption ("titles_split_first_letter") == 1) {
857 1
            $this->entryArray = Book::getAllBooks();
858
        }
859
        else {
860
            list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n);
861
        }
862 4
        $this->idPage = Book::ALL_BOOKS_ID;
863
    }
864 4
}
865 4
866 4
class PageAllBooksLetter extends Page
867 4
{
868
    public function InitializeContent ()
869
    {
870
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n);
871
        $this->idPage = Book::getEntryIdByLetter ($this->idGet);
872
873
        $count = $this->totalNumber;
874
        if ($count == -1)
875
            $count = count ($this->entryArray);
876
877
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet);
878
    }
879 24
}
880 24
881
class PageRecentBooks extends Page
882
{
883 29
    public function InitializeContent ()
884 29
    {
885 29
        $this->title = localize ("recent.title");
886 29
        $this->entryArray = Book::getAllRecentBooks ();
887 29
        $this->idPage = Book::ALL_RECENT_BOOKS_ID;
888 7
    }
889 7
}
890 29
891 22
class PageQueryResult extends Page
892 22
{
893 22
    const SCOPE_TAG = "tag";
894
    const SCOPE_RATING = "rating";
895 29
    const SCOPE_SERIES = "series";
896 23
    const SCOPE_AUTHOR = "author";
897 23
    const SCOPE_BOOK = "book";
898 28
    const SCOPE_PUBLISHER = "publisher";
899 23
900 23
    private function useTypeahead () {
901 25
        return !is_null (getURLParam ("search"));
902 22
    }
903 22
904 24
    private function searchByScope ($scope, $limit = FALSE) {
905 23
        $n = $this->n;
906 23
        $numberPerPage = NULL;
907 23
        $queryNormedAndUp = $this->query;
908 23
        if (useNormAndUp ()) {
909 23
            $queryNormedAndUp = normAndUp ($this->query);
910
        }
911
        if ($limit) {
912
            $n = 1;
913
            $numberPerPage = 5;
914
        }
915 29
        switch ($scope) {
916
            case self::SCOPE_BOOK :
917
                $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, $numberPerPage);
918 22
                break;
919 22
            case self::SCOPE_AUTHOR :
920 22
                $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp);
921 22
                break;
922 22
            case self::SCOPE_SERIES :
923 22
                $array = Serie::getAllSeriesByQuery ($queryNormedAndUp);
924 22
                break;
925
            case self::SCOPE_TAG :
926 22
                $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage);
927 1
                break;
928 1
            case self::SCOPE_PUBLISHER :
929 1
                $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp);
930 22
                break;
931 22
            default:
932 1
                $array = Book::getBooksByQuery (
933 1
                    array ("all" => "%" . $queryNormedAndUp . "%"), $n);
934 1
        }
935 1
936 1
        return $array;
937 22
    }
938 22
939 22
    public function doSearchByCategory () {
940 22
        $database = GetUrlParam (DB);
941 22
        $out = array ();
942 22
        $pagequery = Base::PAGE_OPENSEARCH_QUERY;
943 3
        $dbArray = array ("");
944
        $d = $database;
945 22
        $query = $this->query;
946
        // Special case when no databases were chosen, we search on all databases
947 22
        if (Base::noDatabaseSelected ()) {
948 22
            $dbArray = Base::getDbNameList ();
949 22
            $d = 0;
950 22
        }
951 22
        foreach ($dbArray as $key) {
952 22
            if (Base::noDatabaseSelected ()) {
953
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$d}",
954 22
                                        " ", "text",
955
                                        array ( new LinkNavigation ("?" . DB . "={$d}")), "tt-header"));
956
                Base::getDb ($d);
957
            }
958
            foreach (array (PageQueryResult::SCOPE_BOOK,
959
                            PageQueryResult::SCOPE_AUTHOR,
960
                            PageQueryResult::SCOPE_SERIES,
961 21
                            PageQueryResult::SCOPE_TAG,
962 21
                            PageQueryResult::SCOPE_PUBLISHER) as $key) {
963 21
                if (in_array($key, getCurrentOption ('ignored_categories'))) {
964 21
                    continue;
965 21
                }
966 22
                $array = $this->searchByScope ($key, TRUE);
967 6
968 6
                $i = 0;
969 6
                if (count ($array) == 2 && is_array ($array [0])) {
970 6
                    $total = $array [1];
971 6
                    $array = $array [0];
972 6
                } else {
973 22
                    $total = count($array);
974 22
                }
975 22
                if ($total > 0) {
976 1
                    // Comment to help the perl i18n script
977 1
                    // str_format (localize("bookword", count($array))
978 22
                    // str_format (localize("authorword", count($array))
979 22
                    // str_format (localize("seriesword", count($array))
980
                    // str_format (localize("tagword", count($array))
981
                    // str_format (localize("publisherword", count($array))
982 31
                    array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}",
983
                                        str_format (localize("{$key}word", $total), $total), "text",
984 31
                                        array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&scope={$key}")),
985 31
                                        Base::noDatabaseSelected () ? "" : "tt-header", $total));
986 24
                }
987 24
                if (!Base::noDatabaseSelected () && $this->useTypeahead ()) {
988
                    foreach ($array as $entry) {
989
                        array_push ($this->entryArray, $entry);
990
                        $i++;
991
                        if ($i > 4) { break; };
992
                    }
993
                }
994 7
            }
995
            $d++;
996
            if (Base::noDatabaseSelected ()) {
997 31
                Base::clearDb ();
998
            }
999
        }
1000 31
        return $out;
1001 2
    }
1002 2
1003 2
    public function InitializeContent ()
1004 2
    {
1005 2
        $scope = getURLParam ("scope");
1006 2
        if (empty ($scope)) {
1007 2
            $this->title = str_format (localize ("search.result"), $this->query);
1008 2
        } else {
1009 2
            // Comment to help the perl i18n script
1010 2
            // str_format (localize ("search.result.author"), $this->query)
1011
            // str_format (localize ("search.result.tag"), $this->query)
1012 29
            // str_format (localize ("search.result.series"), $this->query)
1013 22
            // str_format (localize ("search.result.book"), $this->query)
1014 22
            // str_format (localize ("search.result.publisher"), $this->query)
1015
            $this->title = str_format (localize ("search.result.{$scope}"), $this->query);
1016
        }
1017 7
1018 7
        $crit = "%" . $this->query . "%";
1019 2
1020 2
        // Special case when we are doing a search and no database is selected
1021 5
        if (Base::noDatabaseSelected () && !$this->useTypeahead ()) {
1022
            $i = 0;
1023 7
            foreach (Base::getDbNameList () as $key) {
1024
                Base::clearDb ();
1025
                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...
1026
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}",
1027
                                        str_format (localize ("bookword", $totalNumber), $totalNumber), "text",
1028 1
                                        array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber));
1029
                $i++;
1030 1
            }
1031 1
            return;
1032 1
        }
1033
        if (empty ($scope)) {
1034
            $this->doSearchByCategory ();
1035
            return;
1036
        }
1037
1038
        $array = $this->searchByScope ($scope);
1039
        if (count ($array) == 2 && is_array ($array [0])) {
1040
            list ($this->entryArray, $this->totalNumber) = $array;
1041
        } else {
1042
            $this->entryArray = $array;
1043
        }
1044
    }
1045
}
1046
1047
class PageBookDetail extends Page
1048
{
1049
    public function InitializeContent ()
1050
    {
1051
        $this->book = Book::getBookById ($this->idGet);
1052
        $this->title = $this->book->title;
1053
    }
1054
}
1055
1056
class PageAbout extends Page
1057
{
1058
    public function InitializeContent ()
1059
    {
1060
        $this->title = localize ("about.title");
1061
    }
1062
}
1063
1064
class PageCustomize extends Page
1065
{
1066
    private function isChecked ($key, $testedValue = 1) {
1067
        $value = getCurrentOption ($key);
1068
        if (is_array ($value)) {
1069
            if (in_array ($testedValue, $value)) {
1070
                return "checked='checked'";
1071
            }
1072
        } else {
1073
            if ($value == $testedValue) {
1074
                return "checked='checked'";
1075
            }
1076
        }
1077
        return "";
1078
    }
1079
1080
    private function isSelected ($key, $value) {
1081
        if (getCurrentOption ($key) == $value) {
1082
            return "selected='selected'";
1083
        }
1084
        return "";
1085
    }
1086
1087
    private function getStyleList () {
1088
        $result = array ();
1089
        foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) {
1090
            if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) {
1091
                array_push ($result, $m [1]);
1092
            }
1093
        }
1094
        return $result;
1095
    }
1096
1097
    public function InitializeContent ()
1098
    {
1099
        $this->title = localize ("customize.title");
1100
        $this->entryArray = array ();
1101
1102
        $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR,
1103
                                   PageQueryResult::SCOPE_TAG,
1104
                                   PageQueryResult::SCOPE_SERIES,
1105
                                   PageQueryResult::SCOPE_PUBLISHER,
1106
                                   PageQueryResult::SCOPE_RATING,
1107
                                   "language");
1108
1109
        $content = "";
1110
        array_push ($this->entryArray, new Entry ("Template", "",
1111
                                        "<span style='cursor: pointer;' onclick='$.cookie(\"template\", \"bootstrap\", { expires: 365 });window.location=$(\".headleft\").attr(\"href\");'>Click to switch to Bootstrap</span>", "text",
1112
                                        array ()));
1113
        if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) {
1114
            $content .= '<select id="style" onchange="updateCookie (this);">';
1115
            foreach ($this-> getStyleList () as $filename) {
1116
                $content .= "<option value='{$filename}' " . $this->isSelected ("style", $filename) . ">{$filename}</option>";
1117
            }
1118
            $content .= '</select>';
1119
        } else {
1120
            foreach ($this-> getStyleList () as $filename) {
1121
                $content .= "<input type='radio' onchange='updateCookieFromCheckbox (this);' id='style-{$filename}' name='style' value='{$filename}' " . $this->isChecked ("style", $filename) . " /><label for='style-{$filename}'> {$filename} </label>";
1122
            }
1123
        }
1124
        array_push ($this->entryArray, new Entry (localize ("customize.style"), "",
1125
                                        $content, "text",
1126
                                        array ()));
1127
        if (!useServerSideRendering ()) {
1128
            $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="use_fancyapps" ' . $this->isChecked ("use_fancyapps") . ' />';
1129
            array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "",
1130
                                            $content, "text",
1131
                                            array ()));
1132
        }
1133
        $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]+$" />';
1134
        array_push ($this->entryArray, new Entry (localize ("customize.paging"), "",
1135
                                        $content, "text",
1136
                                        array ()));
1137
        $content = '<input type="text" onchange="updateCookie (this);" id="email" value="' . getCurrentOption ("email") . '" />';
1138
        array_push ($this->entryArray, new Entry (localize ("customize.email"), "",
1139
                                        $content, "text",
1140
                                        array ()));
1141
        $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="html_tag_filter" ' . $this->isChecked ("html_tag_filter") . ' />';
1142
        array_push ($this->entryArray, new Entry (localize ("customize.filter"), "",
1143
                                        $content, "text",
1144
                                        array ()));
1145
        $content = "";
1146
        foreach ($ignoredBaseArray as $key) {
1147
            $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s");
1148
            $content .=  '<input type="checkbox" name="ignored_categories[]" onchange="updateCookieFromCheckboxGroup (this);" id="ignored_categories_' . $key . '" ' . $this->isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . '</input> ';
1149
        }
1150
1151
        array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "",
1152
                                        $content, "text",
1153
                                        array ()));
1154
    }
1155
}
1156
1157
abstract class Base
1158
{
1159
    const PAGE_INDEX = "index";
1160
    const PAGE_ALL_AUTHORS = "1";
1161
    const PAGE_AUTHORS_FIRST_LETTER = "2";
1162
    const PAGE_AUTHOR_DETAIL = "3";
1163
    const PAGE_ALL_BOOKS = "4";
1164
    const PAGE_ALL_BOOKS_LETTER = "5";
1165
    const PAGE_ALL_SERIES = "6";
1166
    const PAGE_SERIE_DETAIL = "7";
1167
    const PAGE_OPENSEARCH = "8";
1168 114
    const PAGE_OPENSEARCH_QUERY = "9";
1169 114
    const PAGE_ALL_RECENT_BOOKS = "10";
1170 114
    const PAGE_ALL_TAGS = "11";
1171
    const PAGE_TAG_DETAIL = "12";
1172
    const PAGE_BOOK_DETAIL = "13";
1173 46
    const PAGE_ALL_CUSTOMS = "14";
1174 46
    const PAGE_CUSTOM_DETAIL = "15";
1175 46
    const PAGE_ABOUT = "16";
1176 46
    const PAGE_ALL_LANGUAGES = "17";
1177 46
    const PAGE_LANGUAGE_DETAIL = "18";
1178
    const PAGE_CUSTOMIZE = "19";
1179
    const PAGE_ALL_PUBLISHERS = "20";
1180 45
    const PAGE_PUBLISHER_DETAIL = "21";
1181 45
    const PAGE_ALL_RATINGS = "22";
1182
    const PAGE_RATING_DETAIL = "23";
1183
1184 4
    const COMPATIBILITY_XML_ALDIKO = "aldiko";
1185 4
1186 4
    private static $db = NULL;
1187 4
1188
    public static function isMultipleDatabaseEnabled () {
1189 1
        global $config;
1190
        return is_array ($config['calibre_directory']);
1191
    }
1192
1193 5
    public static function useAbsolutePath () {
1194 5
        global $config;
1195 5
        $path = self::getDbDirectory();
1196 5
        return preg_match ('/^\//', $path) || // Linux /
1197
               preg_match ('/^\w\:/', $path); // Windows X:
1198
    }
1199
1200
    public static function noDatabaseSelected () {
1201
        return self::isMultipleDatabaseEnabled () && is_null (GetUrlParam (DB));
1202 1
    }
1203 1
1204 1
    public static function getDbList () {
1205 1
        global $config;
1206 1
        if (self::isMultipleDatabaseEnabled ()) {
1207
            return $config['calibre_directory'];
1208
        } else {
1209 1
            return array ("" => $config['calibre_directory']);
1210 1
        }
1211
    }
1212
1213
    public static function getDbNameList () {
1214
        global $config;
1215 96
        if (self::isMultipleDatabaseEnabled ()) {
1216 96
            return array_keys ($config['calibre_directory']);
1217 96
        } else {
1218 9
            return array ("");
1219 9
        }
1220
    }
1221
1222 9
    public static function getDbName ($database = NULL) {
1223 9
        global $config;
1224
        if (self::isMultipleDatabaseEnabled ()) {
1225 87
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1226
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1227
                self::error ($database);
1228
            }
1229 67
            $array = array_keys ($config['calibre_directory']);
1230 67
            return  $array[$database];
1231
        }
1232
        return "";
1233 2
    }
1234 2
1235
    public static function getDbDirectory ($database = NULL) {
1236
        global $config;
1237 2
        if (self::isMultipleDatabaseEnabled ()) {
1238
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1239
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1240 132
                self::error ($database);
1241 132
            }
1242
            $array = array_values ($config['calibre_directory']);
1243 67
            return  $array[$database];
1244 66
        }
1245 66
        return $config['calibre_directory'];
1246 7
    }
1247 7
1248 66
1249 2
    public static function getDbFileName ($database = NULL) {
1250
        return self::getDbDirectory ($database) .'metadata.db';
1251 67
    }
1252 2
1253
    private static function error ($database) {
1254 66
        if (php_sapi_name() != "cli") {
1255 131
            header("location: checkconfig.php?err=1");
1256
        }
1257
        throw new Exception("Database <{$database}> not found.");
1258 4
    }
1259 4
1260 3
    public static function getDb ($database = NULL) {
1261 3
        if (is_null (self::$db)) {
1262 2
            try {
1263 2
                if (is_readable (self::getDbFileName ($database))) {
1264 1
                    self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
1265 1
                    if (useNormAndUp ()) {
1266
                        self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1);
1267 2
                    }
1268
                } else {
1269
                    self::error ($database);
1270 64
                }
1271 64
            } catch (Exception $e) {
1272 64
                self::error ($database);
1273
            }
1274 13
        }
1275 13
        return self::$db;
1276
    }
1277
1278 8
    public static function checkDatabaseAvailability () {
1279 8
        if (self::noDatabaseSelected ()) {
1280 7
            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...
1281 7
                self::getDb ($i);
1282 8
                self::clearDb ();
1283 8
            }
1284 8
        } else {
1285 8
            self::getDb ();
1286 8
        }
1287 8
        return true;
1288
    }
1289
1290 35
    public static function clearDb () {
1291 35
        self::$db = NULL;
1292 35
    }
1293 35
1294
    public static function executeQuerySingle ($query, $database = NULL) {
1295 25
        return self::getDb ($database)->query($query)->fetchColumn();
1296 25
    }
1297 17
1298 17
    public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL) {
1299 8
        if (!$numberOfString) {
1300
            $numberOfString = $table . ".alphabetical";
1301 25
        }
1302 25
        $count = self::executeQuerySingle ('select count(*) from ' . $table);
1303 25
        if ($count == 0) return NULL;
1304 25
        $entry = new Entry (localize($table . ".title"), $id,
1305 35
            str_format (localize($numberOfString, $count), $count), "text",
1306
            array ( new LinkNavigation ("?page=".$pageId)), "", $count);
1307
        return $entry;
1308 73
    }
1309 73
1310
    public static function getEntryArrayWithBookNumber ($query, $columns, $params, $category) {
1311 73
        /* @var $result PDOStatement */
1312 7
1313 7
        list (, $result) = self::executeQuery ($query, $columns, "", $params, -1);
1314 7
        $entryArray = array();
1315
        while ($post = $result->fetchObject ())
1316 73
        {
1317 71
            /* @var $instance Author|Tag|Serie|Publisher */
1318 71
1319
            $instance = new $category ($post);
1320 73
            if (property_exists($post, "sort")) {
1321 73
                $title = $post->sort;
1322
            } else {
1323 28
                $title = $post->name;
1324 28
            }
1325 28
            array_push ($entryArray, new Entry ($title, $instance->getEntryId (),
1326
                str_format (localize("bookword", $post->count), $post->count), "text",
1327
                array ( new LinkNavigation ($instance->getUri ())), "", $post->count));
1328 28
        }
1329 28
        return $entryArray;
1330 28
    }
1331
1332 73
    public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL) {
1333 73
        $totalResult = -1;
1334 73
1335
        if (useNormAndUp ()) {
1336
            $query = preg_replace("/upper/", "normAndUp", $query);
1337
            $columns = preg_replace("/upper/", "normAndUp", $columns);
1338
        }
1339
1340
        if (is_null ($numberPerPage)) {
1341
            $numberPerPage = getCurrentOption ("max_item_per_page");
1342
        }
1343
1344
        if ($numberPerPage != -1 && $n != -1)
1345
        {
1346
            // First check total number of results
1347
            $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
1348
            $result->execute ($params);
1349
            $totalResult = $result->fetchColumn ();
1350
1351
            // Next modify the query and params
1352
            $query .= " limit ?, ?";
1353
            array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage);
1354
        }
1355
1356
        $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
1357
        $result->execute ($params);
1358
        return array ($totalResult, $result);
1359
    }
1360
1361
}
1362