Completed
Pull Request — master (#269)
by
unknown
02:56
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
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 134
    if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") {
65 34
        return $_GET[$name];
66
    }
67 122
    return $default;
68
}
69
70
function getCurrentOption ($option) {
71 100
    global $config;
72 100
    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 98
    if ($option == "style") {
80 2
        return "default";
81
    }
82
83 98
    if (isset($config ["cops_" . $option])) {
84 98
        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 69
    return $url . "?v=" . VERSION;
100
}
101
102
function xml2xhtml($xml) {
103 37
    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 37
    '), $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 37
    $errors = libxml_get_errors();
140
141 37
    foreach ($errors as $error) {
142
        if ($error->code == 801) return false;
143 37
    }
144 37
    return true;
145
}
146
147
function html2xhtml ($html) {
148 37
    $doc = new DOMDocument();
149 37
    libxml_use_internal_errors(true);
150
151 37
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
152 37
                        $html  . '</body></html>'); // Load the HTML
153 37
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
154 37
    $output = xml2xhtml($output);
155 37
    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 37
        $output = $matches [1]; // Remove <html><body>
157 37
    }
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 37
    if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
168
169 37
    libxml_use_internal_errors(false);
170 37
    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 116
    $args = func_get_args();
179 116
    $format = array_shift($args);
180
181 116
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
182 116
    $offset = 0;
183 116
    foreach ($matches[1] as $data) {
184 116
        $i = $data[0];
185 116
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
186 116
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
187 116
    }
188
189 116
    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 136
    global $config;
272 136
    if ($count == 0)
273 136
        $phrase .= ".none";
274 136
    if ($count == 1)
275 136
        $phrase .= ".one";
276 136
    if ($count > 1)
277 136
        $phrase .= ".many";
278
279
    /* Static keyword is used to ensure the file is loaded only once */
280 136
    static $translations = NULL;
281 136
    if ($reset) {
282 16
        $translations = NULL;
283 16
    }
284
    /* If no instance of $translations has occured load the language file */
285 136
    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 136
    if (array_key_exists ($phrase, $translations)) {
310 136
        return $translations[$phrase];
311
    }
312 3
    return $phrase;
313
}
314
315
function addURLParameter($urlParams, $paramName, $paramValue) {
316 61
    if (empty ($urlParams)) {
317 51
        $urlParams = "";
318 51
    }
319 61
    $start = "";
320 61
    if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
321 15
        $start = "?";
322 15
        $urlParams = $matches[1];
323 15
    }
324 61
    $params = array();
325 61
    parse_str($urlParams, $params);
326 61
    if (empty ($paramValue) && $paramValue != 0) {
327
        unset ($params[$paramName]);
328
    } else {
329 61
        $params[$paramName] = $paramValue;
330
    }
331 61
    return $start . http_build_query($params);
332
}
333
334
function useNormAndUp () {
335 144
    global $config;
336 144
    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 117
    public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
364 117
        $this->href = $phref;
365 117
        $this->type = $ptype;
366 117
        $this->rel = $prel;
367 117
        $this->title = $ptitle;
368 117
        $this->facetGroup = $pfacetGroup;
369 117
        $this->activeFacet = $pactiveFacet;
370 117
    }
371
372 11
    public function hrefXhtml () {
373 11
        return $this->href;
374
    }
375
376 116
    public function getScriptName() {
377 116
        $parts = explode('/', $_SERVER["SCRIPT_NAME"]);
378 116
        return $parts[count($parts) - 1];
379
    }
380
}
381
382
class LinkNavigation extends Link
383
{
384 116
    public function __construct($phref, $prel = NULL, $ptitle = NULL) {
385 116
        parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
386 116
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
387 116
        if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
388 116
        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...
389
            $this->href = "index.php" . $this->href;
390
        } else {
391 116
            $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...
392
        }
393 116
    }
394
}
395
396
class LinkFacet extends Link
397
{
398 1
    public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
399 1
        parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet);
400 1
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
401 1
        $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...
402 1
    }
403
}
404
405
class Entry
406
{
407
    public $title;
408
    public $id;
409
    public $content;
410
    public $numberOfElement;
411
    public $contentType;
412
    public $linkArray;
413
    public $localUpdated;
414
    public $className;
415
    private static $updated = NULL;
416
417
    public static $icons = array(
418
        Author::ALL_AUTHORS_ID           => 'images/author.png',
419
        Serie::ALL_SERIES_ID             => 'images/serie.png',
420
        Book::ALL_RECENT_BOOKS_ID        => 'images/recent.png',
421
        Tag::ALL_TAGS_ID                 => 'images/tag.png',
422
        Language::ALL_LANGUAGES_ID       => 'images/language.png',
423
        CustomColumnType::ALL_CUSTOMS_ID => 'images/custom.png',
424
        Rating::ALL_RATING_ID            => 'images/rating.png',
425
        "cops:books$"                    => 'images/allbook.png',
426
        "cops:books:letter"              => 'images/allbook.png',
427
        Publisher::ALL_PUBLISHERS_ID     => 'images/publisher.png'
428
    );
429
430
    public function getUpdatedTime () {
431
        if (!is_null ($this->localUpdated)) {
432
            return date (DATE_ATOM, $this->localUpdated);
433
        }
434
        if (is_null (self::$updated)) {
435
            self::$updated = time();
436
        }
437
        return date (DATE_ATOM, self::$updated);
438
    }
439
440 7
    public function getNavLink () {
441 7
        foreach ($this->linkArray as $link) {
442
            /* @var $link LinkNavigation */
443
444 7
            if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
445
446 7
            return $link->hrefXhtml ();
447
        }
448
        return "#";
449
    }
450
451 109
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) {
452 109
        global $config;
453 109
        $this->title = $ptitle;
454 109
        $this->id = $pid;
455 109
        $this->content = $pcontent;
456 109
        $this->contentType = $pcontentType;
457 109
        $this->linkArray = $plinkArray;
458 109
        $this->className = $pclass;
459 109
        $this->numberOfElement = $pcount;
460
461 109
        if ($config['cops_show_icons'] == 1)
462 109
        {
463 109
            foreach (self::$icons as $reg => $image)
464
            {
465 109
                if (preg_match ("/" . $reg . "/", $pid)) {
466 69
                    array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE));
467 69
                    break;
468
                }
469 109
            }
470 109
        }
471
472 109
        if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $this->id);
473 109
    }
474
}
475
476
class EntryBook extends Entry
477
{
478
    public $book;
479
480
    /**
481
     * EntryBook constructor.
482
     * @param string $ptitle
483
     * @param integer $pid
484
     * @param string $pcontent
485
     * @param string $pcontentType
486
     * @param array $plinkArray
487
     * @param Book $pbook
488
     */
489 41
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) {
490 41
        parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray);
491 41
        $this->book = $pbook;
492 41
        $this->localUpdated = $pbook->timestamp;
493 41
    }
494
495
    public function getCoverThumbnail () {
496
        foreach ($this->linkArray as $link) {
497
            /* @var $link LinkNavigation */
498
499
            if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
500
                return $link->hrefXhtml ();
501
        }
502
        return null;
503
    }
504
505
    public function getCover () {
506
        foreach ($this->linkArray as $link) {
507
            /* @var $link LinkNavigation */
508
509
            if ($link->rel == Link::OPDS_IMAGE_TYPE)
510
                return $link->hrefXhtml ();
511
        }
512
        return null;
513
    }
514
}
515
516
class Page
517
{
518
    public $title;
519
    public $subtitle = "";
520
    public $authorName = "";
521
    public $authorUri = "";
522
    public $authorEmail = "";
523
    public $idPage;
524
    public $idGet;
525
    public $query;
526
    public $favicon;
527
    public $n;
528
    public $book;
529
    public $totalNumber = -1;
530
531
    /* @var Entry[] */
532
    public $entryArray = array();
533
534 102
    public static function getPage ($pageId, $id, $query, $n)
535
    {
536
        switch ($pageId) {
537 102
            case Base::PAGE_ALL_AUTHORS :
538 3
                return new PageAllAuthors ($id, $query, $n);
539 99
            case Base::PAGE_AUTHORS_FIRST_LETTER :
540 1
                return new PageAllAuthorsLetter ($id, $query, $n);
541 98
            case Base::PAGE_AUTHOR_DETAIL :
542 7
                return new PageAuthorDetail ($id, $query, $n);
543 91
            case Base::PAGE_ALL_TAGS :
544 2
                return new PageAllTags ($id, $query, $n);
545 89
            case Base::PAGE_TAG_DETAIL :
546 1
                return new PageTagDetail ($id, $query, $n);
547 88
            case Base::PAGE_ALL_LANGUAGES :
548 2
                return new PageAllLanguages ($id, $query, $n);
549 86
            case Base::PAGE_LANGUAGE_DETAIL :
550 1
                return new PageLanguageDetail ($id, $query, $n);
551 85
            case Base::PAGE_ALL_CUSTOMS :
552 12
                return new PageAllCustoms ($id, $query, $n);
553 73
            case Base::PAGE_CUSTOM_DETAIL :
554 4
                return new PageCustomDetail ($id, $query, $n);
555 69
            case Base::PAGE_ALL_RATINGS :
556 1
                return new PageAllRating ($id, $query, $n);
557 68
            case Base::PAGE_RATING_DETAIL :
558 1
                return new PageRatingDetail ($id, $query, $n);
559 67
            case Base::PAGE_ALL_SERIES :
560 2
                return new PageAllSeries ($id, $query, $n);
561 65
            case Base::PAGE_ALL_BOOKS :
562 3
                return new PageAllBooks ($id, $query, $n);
563 62
            case Base::PAGE_ALL_BOOKS_LETTER:
564 1
                return new PageAllBooksLetter ($id, $query, $n);
565 61
            case Base::PAGE_ALL_RECENT_BOOKS :
566 4
                return new PageRecentBooks ($id, $query, $n);
567 57
            case Base::PAGE_SERIE_DETAIL :
568 1
                return new PageSerieDetail ($id, $query, $n);
569 56
            case Base::PAGE_OPENSEARCH_QUERY :
570 31
                return new PageQueryResult ($id, $query, $n);
571 25
            case Base::PAGE_BOOK_DETAIL :
572 1
                return new PageBookDetail ($id, $query, $n);
573 24
            case Base::PAGE_ALL_PUBLISHERS:
574 2
                return new PageAllPublishers ($id, $query, $n);
575 22
            case Base::PAGE_PUBLISHER_DETAIL :
576 1
                return new PagePublisherDetail ($id, $query, $n);
577 21
            case Base::PAGE_ABOUT :
578
                return new PageAbout ($id, $query, $n);
579 21
            case Base::PAGE_CUSTOMIZE :
580
                return new PageCustomize ($id, $query, $n);
581 21
            default:
582 21
                $page = new Page ($id, $query, $n);
583 21
                $page->idPage = "cops:catalog";
584 21
                return $page;
585 21
        }
586
    }
587
588 102
    public function __construct($pid, $pquery, $pn) {
589 102
        global $config;
590
591 102
        $this->idGet = $pid;
592 102
        $this->query = $pquery;
593 102
        $this->n = $pn;
594 102
        $this->favicon = $config['cops_icon'];
595 102
        $this->authorName = empty($config['cops_author_name']) ? utf8_encode('Sébastien Lucas') : $config['cops_author_name'];
596 102
        $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri'];
597 102
        $this->authorEmail = empty($config['cops_author_email']) ? '[email protected]' : $config['cops_author_email'];
598 102
    }
599
600 21
    public function InitializeContent ()
601
    {
602 21
        global $config;
603 21
        $this->title = $config['cops_title_default'];
604 21
        $this->subtitle = $config['cops_subtitle_default'];
605 21
        if (Base::noDatabaseSelected ()) {
606 2
            $i = 0;
607 2
            foreach (Base::getDbNameList () as $key) {
608 2
                $nBooks = Book::getBookCount ($i);
609 2
                array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog",
610 2
                                        str_format (localize ("bookword", $nBooks), $nBooks), "text",
611 2
                                        array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks));
612 2
                $i++;
613 2
                Base::clearDb ();
614 2
            }
615 2
        } else {
616 19
            if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) {
617 18
                array_push ($this->entryArray, Author::getCount());
618 18
            }
619 19
            if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) {
620 18
                $series = Serie::getCount();
621 18
                if (!is_null ($series)) array_push ($this->entryArray, $series);
622 18
            }
623 19
            if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) {
624 18
                $publisher = Publisher::getCount();
625 18
                if (!is_null ($publisher)) array_push ($this->entryArray, $publisher);
626 18
            }
627 19
            if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) {
628 18
                $tags = Tag::getCount();
629 18
                if (!is_null ($tags)) array_push ($this->entryArray, $tags);
630 18
            }
631 19
            if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) {
632 19
                $rating = Rating::getCount();
633 19
                if (!is_null ($rating)) array_push ($this->entryArray, $rating);
634 19
            }
635 19
            if (!in_array ("language", getCurrentOption ('ignored_categories'))) {
636 18
                $languages = Language::getCount();
637 18
                if (!is_null ($languages)) array_push ($this->entryArray, $languages);
638 18
            }
639 19
            foreach ($config['cops_calibre_custom_column'] as $lookup) {
640 15
                $customColumn = CustomColumnType::createByLookup($lookup);
641 15
                if (!is_null ($customColumn) && $customColumn->isSearchable()) {
642 14
                    array_push ($this->entryArray, $customColumn->getCount());
643 14
                }
644 19
            }
645 19
            $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...
646
647 19
            if (Base::isMultipleDatabaseEnabled ()) $this->title =  Base::getDbName ();
648
        }
649 21
    }
650
651 17
    public function isPaginated ()
652
    {
653 17
        return (getCurrentOption ("max_item_per_page") != -1 &&
654 17
                $this->totalNumber != -1 &&
655 17
                $this->totalNumber > getCurrentOption ("max_item_per_page"));
656
    }
657
658 2
    public function getNextLink ()
659
    {
660 2
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
661 2
        if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) {
662 1
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate"));
663
        }
664 1
        return NULL;
665
    }
666
667 2
    public function getPrevLink ()
668
    {
669 2
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
670 2
        if ($this->n > 1) {
671 1
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate"));
672
        }
673 2
        return NULL;
674
    }
675
676 2
    public function getMaxPage ()
677
    {
678 2
        return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page"));
679
    }
680
681 70
    public function containsBook ()
682
    {
683 70
        if (count ($this->entryArray) == 0) return false;
684 68
        if (get_class ($this->entryArray [0]) == "EntryBook") return true;
685 46
        return false;
686
    }
687
}
688
689
class PageAllAuthors extends Page
690
{
691 3
    public function InitializeContent ()
692
    {
693 3
        $this->title = localize("authors.title");
694 3
        if (getCurrentOption ("author_split_first_letter") == 1) {
695 2
            $this->entryArray = Author::getAllAuthorsByFirstLetter();
696 2
        }
697
        else {
698 1
            $this->entryArray = Author::getAllAuthors();
699
        }
700 3
        $this->idPage = Author::ALL_AUTHORS_ID;
701 3
    }
702
}
703
704
class PageAllAuthorsLetter extends Page
705
{
706 1
    public function InitializeContent ()
707
    {
708 1
        $this->idPage = Author::getEntryIdByLetter ($this->idGet);
709 1
        $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet);
710 1
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet);
711 1
    }
712
}
713
714
class PageAuthorDetail extends Page
715
{
716 7
    public function InitializeContent ()
717
    {
718 7
        $author = Author::getAuthorById ($this->idGet);
719 7
        $this->idPage = $author->getEntryId ();
720 7
        $this->title = $author->name;
721 7
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n);
722 7
    }
723
}
724
725
class PageAllPublishers extends Page
726
{
727 2
    public function InitializeContent ()
728
    {
729 2
        $this->title = localize("publishers.title");
730 2
        $this->entryArray = Publisher::getAllPublishers();
731 2
        $this->idPage = Publisher::ALL_PUBLISHERS_ID;
732 2
    }
733
}
734
735
class PagePublisherDetail extends Page
736
{
737 1
    public function InitializeContent ()
738
    {
739 1
        $publisher = Publisher::getPublisherById ($this->idGet);
740 1
        $this->title = $publisher->name;
741 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n);
742 1
        $this->idPage = $publisher->getEntryId ();
743 1
    }
744
}
745
746
class PageAllTags extends Page
747
{
748 2
    public function InitializeContent ()
749
    {
750 2
        $this->title = localize("tags.title");
751 2
        $this->entryArray = Tag::getAllTags();
752 2
        $this->idPage = Tag::ALL_TAGS_ID;
753 2
    }
754
}
755
756
class PageAllLanguages extends Page
757
{
758 2
    public function InitializeContent ()
759
    {
760 2
        $this->title = localize("languages.title");
761 2
        $this->entryArray = Language::getAllLanguages();
762 2
        $this->idPage = Language::ALL_LANGUAGES_ID;
763 2
    }
764
}
765
766
class PageCustomDetail extends Page
767
{
768 4
    public function InitializeContent ()
769
    {
770 4
        $customId = getURLParam ("custom", NULL);
771 4
        $custom = CustomColumn::createCustom ($customId, $this->idGet);
772 4
        $this->idPage = $custom->getEntryId ();
773 4
        $this->title = $custom->value;
774 4
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($custom, $this->idGet, $this->n);
775 4
    }
776
}
777
778
class PageAllCustoms extends Page
779
{
780 12
    public function InitializeContent ()
781
    {
782 12
        $customId = getURLParam ("custom", NULL);
783 12
        $columnType = CustomColumnType::createByCustomID($customId);
784
        
785 12
        $this->title = $columnType->getTitle();
786 12
        $this->entryArray = $columnType->getAllCustomValues();
787 12
        $this->idPage = $columnType->getAllCustomsId();
788 12
    }
789
}
790
791
class PageTagDetail extends Page
792
{
793 1
    public function InitializeContent ()
794
    {
795 1
        $tag = Tag::getTagById ($this->idGet);
796 1
        $this->idPage = $tag->getEntryId ();
797 1
        $this->title = $tag->name;
798 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n);
799 1
    }
800
}
801
802
class PageLanguageDetail extends Page
803
{
804 1
    public function InitializeContent ()
805
    {
806 1
        $language = Language::getLanguageById ($this->idGet);
807 1
        $this->idPage = $language->getEntryId ();
808 1
        $this->title = $language->lang_code;
809 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n);
810 1
    }
811
}
812
813
class PageAllSeries extends Page
814
{
815 2
    public function InitializeContent ()
816
    {
817 2
        $this->title = localize("series.title");
818 2
        $this->entryArray = Serie::getAllSeries();
819 2
        $this->idPage = Serie::ALL_SERIES_ID;
820 2
    }
821
}
822
823
class PageSerieDetail extends Page
824
{
825 1
    public function InitializeContent ()
826
    {
827 1
        $serie = Serie::getSerieById ($this->idGet);
828 1
        $this->title = $serie->name;
829 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n);
830 1
        $this->idPage = $serie->getEntryId ();
831 1
    }
832
}
833
834
class PageAllRating extends Page
835
{
836 1
    public function InitializeContent ()
837
    {
838 1
        $this->title = localize("ratings.title");
839 1
        $this->entryArray = Rating::getAllRatings();
840 1
        $this->idPage = Rating::ALL_RATING_ID;
841 1
    }
842
}
843
844
class PageRatingDetail extends Page
845
{
846 1
    public function InitializeContent ()
847
    {
848 1
        $rating = Rating::getRatingById ($this->idGet);
849 1
        $this->idPage = $rating->getEntryId ();
850 1
        $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2);
851 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n);
852 1
    }
853
}
854
855
class PageAllBooks extends Page
856
{
857 3
    public function InitializeContent ()
858
    {
859 3
        $this->title = localize ("allbooks.title");
860 3
        if (getCurrentOption ("titles_split_first_letter") == 1) {
861 2
            $this->entryArray = Book::getAllBooks();
862 2
        }
863
        else {
864 1
            list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n);
865
        }
866 3
        $this->idPage = Book::ALL_BOOKS_ID;
867 3
    }
868
}
869
870
class PageAllBooksLetter extends Page
871
{
872 1
    public function InitializeContent ()
873
    {
874 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n);
875 1
        $this->idPage = Book::getEntryIdByLetter ($this->idGet);
876
877 1
        $count = $this->totalNumber;
878 1
        if ($count == -1)
879 1
            $count = count ($this->entryArray);
880
881 1
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet);
882 1
    }
883
}
884
885
class PageRecentBooks extends Page
886
{
887 4
    public function InitializeContent ()
888
    {
889 4
        $this->title = localize ("recent.title");
890 4
        $this->entryArray = Book::getAllRecentBooks ();
891 4
        $this->idPage = Book::ALL_RECENT_BOOKS_ID;
892 4
    }
893
}
894
895
class PageQueryResult extends Page
896
{
897
    const SCOPE_TAG = "tag";
898
    const SCOPE_RATING = "rating";
899
    const SCOPE_SERIES = "series";
900
    const SCOPE_AUTHOR = "author";
901
    const SCOPE_BOOK = "book";
902
    const SCOPE_PUBLISHER = "publisher";
903
904 24
    private function useTypeahead () {
905 24
        return !is_null (getURLParam ("search"));
906
    }
907
908 29
    private function searchByScope ($scope, $limit = FALSE) {
909 29
        $n = $this->n;
910 29
        $numberPerPage = NULL;
911 29
        $queryNormedAndUp = $this->query;
912 29
        if (useNormAndUp ()) {
913 7
            $queryNormedAndUp = normAndUp ($this->query);
914 7
        }
915 29
        if ($limit) {
916 22
            $n = 1;
917 22
            $numberPerPage = 5;
918 22
        }
919
        switch ($scope) {
920 29
            case self::SCOPE_BOOK :
921 23
                $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, $numberPerPage);
922 23
                break;
923 28
            case self::SCOPE_AUTHOR :
924 23
                $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp);
925 23
                break;
926 25
            case self::SCOPE_SERIES :
927 22
                $array = Serie::getAllSeriesByQuery ($queryNormedAndUp);
928 22
                break;
929 24
            case self::SCOPE_TAG :
930 23
                $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage);
931 23
                break;
932 23
            case self::SCOPE_PUBLISHER :
933 23
                $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp);
934 23
                break;
935
            default:
936
                $array = Book::getBooksByQuery (
937
                    array ("all" => "%" . $queryNormedAndUp . "%"), $n);
938
        }
939
940 29
        return $array;
941
    }
942
943 22
    public function doSearchByCategory () {
944 22
        $database = GetUrlParam (DB);
945 22
        $out = array ();
946 22
        $pagequery = Base::PAGE_OPENSEARCH_QUERY;
947 22
        $dbArray = array ("");
948 22
        $d = $database;
949 22
        $query = $this->query;
950
        // Special case when no databases were chosen, we search on all databases
951 22
        if (Base::noDatabaseSelected ()) {
952 1
            $dbArray = Base::getDbNameList ();
953 1
            $d = 0;
954 1
        }
955 22
        foreach ($dbArray as $key) {
956 22
            if (Base::noDatabaseSelected ()) {
957 1
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$d}",
958 1
                                        " ", "text",
959 1
                                        array ( new LinkNavigation ("?" . DB . "={$d}")), "tt-header"));
960 1
                Base::getDb ($d);
961 1
            }
962 22
            foreach (array (PageQueryResult::SCOPE_BOOK,
963 22
                            PageQueryResult::SCOPE_AUTHOR,
964 22
                            PageQueryResult::SCOPE_SERIES,
965 22
                            PageQueryResult::SCOPE_TAG,
966 22
                            PageQueryResult::SCOPE_PUBLISHER) as $key) {
967 22
                if (in_array($key, getCurrentOption ('ignored_categories'))) {
968 3
                    continue;
969
                }
970 22
                $array = $this->searchByScope ($key, TRUE);
971
972 22
                $i = 0;
973 22
                if (count ($array) == 2 && is_array ($array [0])) {
974 22
                    $total = $array [1];
975 22
                    $array = $array [0];
976 22
                } else {
977 22
                    $total = count($array);
978
                }
979 22
                if ($total > 0) {
980
                    // Comment to help the perl i18n script
981
                    // str_format (localize("bookword", count($array))
982
                    // str_format (localize("authorword", count($array))
983
                    // str_format (localize("seriesword", count($array))
984
                    // str_format (localize("tagword", count($array))
985
                    // str_format (localize("publisherword", count($array))
986 21
                    array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}",
987 21
                                        str_format (localize("{$key}word", $total), $total), "text",
988 21
                                        array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&scope={$key}")),
989 21
                                        Base::noDatabaseSelected () ? "" : "tt-header", $total));
990 21
                }
991 22
                if (!Base::noDatabaseSelected () && $this->useTypeahead ()) {
992 6
                    foreach ($array as $entry) {
993 6
                        array_push ($this->entryArray, $entry);
994 6
                        $i++;
995 6
                        if ($i > 4) { break; };
996 6
                    }
997 6
                }
998 22
            }
999 22
            $d++;
1000 22
            if (Base::noDatabaseSelected ()) {
1001 1
                Base::clearDb ();
1002 1
            }
1003 22
        }
1004 22
        return $out;
1005
    }
1006
1007 31
    public function InitializeContent ()
1008
    {
1009 31
        $scope = getURLParam ("scope");
1010 31
        if (empty ($scope)) {
1011 24
            $this->title = str_format (localize ("search.result"), $this->query);
1012 24
        } else {
1013
            // Comment to help the perl i18n script
1014
            // str_format (localize ("search.result.author"), $this->query)
1015
            // str_format (localize ("search.result.tag"), $this->query)
1016
            // str_format (localize ("search.result.series"), $this->query)
1017
            // str_format (localize ("search.result.book"), $this->query)
1018
            // str_format (localize ("search.result.publisher"), $this->query)
1019 7
            $this->title = str_format (localize ("search.result.{$scope}"), $this->query);
1020
        }
1021
1022 31
        $crit = "%" . $this->query . "%";
1023
1024
        // Special case when we are doing a search and no database is selected
1025 31
        if (Base::noDatabaseSelected () && !$this->useTypeahead ()) {
1026 2
            $i = 0;
1027 2
            foreach (Base::getDbNameList () as $key) {
1028 2
                Base::clearDb ();
1029 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...
1030 2
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}",
1031 2
                                        str_format (localize ("bookword", $totalNumber), $totalNumber), "text",
1032 2
                                        array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber));
1033 2
                $i++;
1034 2
            }
1035 2
            return;
1036
        }
1037 29
        if (empty ($scope)) {
1038 22
            $this->doSearchByCategory ();
1039 22
            return;
1040
        }
1041
1042 7
        $array = $this->searchByScope ($scope);
1043 7
        if (count ($array) == 2 && is_array ($array [0])) {
1044 2
            list ($this->entryArray, $this->totalNumber) = $array;
1045 2
        } else {
1046 5
            $this->entryArray = $array;
1047
        }
1048 7
    }
1049
}
1050
1051
class PageBookDetail extends Page
1052
{
1053 1
    public function InitializeContent ()
1054
    {
1055 1
        $this->book = Book::getBookById ($this->idGet);
1056 1
        $this->title = $this->book->title;
1057 1
    }
1058
}
1059
1060
class PageAbout extends Page
1061
{
1062
    public function InitializeContent ()
1063
    {
1064
        $this->title = localize ("about.title");
1065
    }
1066
}
1067
1068
class PageCustomize extends Page
1069
{
1070
    private function isChecked ($key, $testedValue = 1) {
1071
        $value = getCurrentOption ($key);
1072
        if (is_array ($value)) {
1073
            if (in_array ($testedValue, $value)) {
1074
                return "checked='checked'";
1075
            }
1076
        } else {
1077
            if ($value == $testedValue) {
1078
                return "checked='checked'";
1079
            }
1080
        }
1081
        return "";
1082
    }
1083
1084
    private function isSelected ($key, $value) {
1085
        if (getCurrentOption ($key) == $value) {
1086
            return "selected='selected'";
1087
        }
1088
        return "";
1089
    }
1090
1091
    private function getStyleList () {
1092
        $result = array ();
1093
        foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) {
1094
            if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) {
1095
                array_push ($result, $m [1]);
1096
            }
1097
        }
1098
        return $result;
1099
    }
1100
1101
    public function InitializeContent ()
1102
    {
1103
        $this->title = localize ("customize.title");
1104
        $this->entryArray = array ();
1105
1106
        $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR,
1107
                                   PageQueryResult::SCOPE_TAG,
1108
                                   PageQueryResult::SCOPE_SERIES,
1109
                                   PageQueryResult::SCOPE_PUBLISHER,
1110
                                   PageQueryResult::SCOPE_RATING,
1111
                                   "language");
1112
1113
        $content = "";
1114
        array_push ($this->entryArray, new Entry ("Template", "",
1115
                                        "<span style='cursor: pointer;' onclick='$.cookie(\"template\", \"bootstrap\", { expires: 365 });window.location=$(\".headleft\").attr(\"href\");'>Click to switch to Bootstrap</span>", "text",
1116
                                        array ()));
1117
        if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) {
1118
            $content .= '<select id="style" onchange="updateCookie (this);">';
1119
            foreach ($this-> getStyleList () as $filename) {
1120
                $content .= "<option value='{$filename}' " . $this->isSelected ("style", $filename) . ">{$filename}</option>";
1121
            }
1122
            $content .= '</select>';
1123
        } else {
1124
            foreach ($this-> getStyleList () as $filename) {
1125
                $content .= "<input type='radio' onchange='updateCookieFromCheckbox (this);' id='style-{$filename}' name='style' value='{$filename}' " . $this->isChecked ("style", $filename) . " /><label for='style-{$filename}'> {$filename} </label>";
1126
            }
1127
        }
1128
        array_push ($this->entryArray, new Entry (localize ("customize.style"), "",
1129
                                        $content, "text",
1130
                                        array ()));
1131
        if (!useServerSideRendering ()) {
1132
            $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="use_fancyapps" ' . $this->isChecked ("use_fancyapps") . ' />';
1133
            array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "",
1134
                                            $content, "text",
1135
                                            array ()));
1136
        }
1137
        $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]+$" />';
1138
        array_push ($this->entryArray, new Entry (localize ("customize.paging"), "",
1139
                                        $content, "text",
1140
                                        array ()));
1141
        $content = '<input type="text" onchange="updateCookie (this);" id="email" value="' . getCurrentOption ("email") . '" />';
1142
        array_push ($this->entryArray, new Entry (localize ("customize.email"), "",
1143
                                        $content, "text",
1144
                                        array ()));
1145
        $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="html_tag_filter" ' . $this->isChecked ("html_tag_filter") . ' />';
1146
        array_push ($this->entryArray, new Entry (localize ("customize.filter"), "",
1147
                                        $content, "text",
1148
                                        array ()));
1149
        $content = "";
1150
        foreach ($ignoredBaseArray as $key) {
1151
            $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s");
1152
            $content .=  '<input type="checkbox" name="ignored_categories[]" onchange="updateCookieFromCheckboxGroup (this);" id="ignored_categories_' . $key . '" ' . $this->isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . '</input> ';
1153
        }
1154
1155
        array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "",
1156
                                        $content, "text",
1157
                                        array ()));
1158
    }
1159
}
1160
1161
abstract class Base
1162
{
1163
    const PAGE_INDEX = "index";
1164
    const PAGE_ALL_AUTHORS = "1";
1165
    const PAGE_AUTHORS_FIRST_LETTER = "2";
1166
    const PAGE_AUTHOR_DETAIL = "3";
1167
    const PAGE_ALL_BOOKS = "4";
1168
    const PAGE_ALL_BOOKS_LETTER = "5";
1169
    const PAGE_ALL_SERIES = "6";
1170
    const PAGE_SERIE_DETAIL = "7";
1171
    const PAGE_OPENSEARCH = "8";
1172
    const PAGE_OPENSEARCH_QUERY = "9";
1173
    const PAGE_ALL_RECENT_BOOKS = "10";
1174
    const PAGE_ALL_TAGS = "11";
1175
    const PAGE_TAG_DETAIL = "12";
1176
    const PAGE_BOOK_DETAIL = "13";
1177
    const PAGE_ALL_CUSTOMS = "14";
1178
    const PAGE_CUSTOM_DETAIL = "15";
1179
    const PAGE_ABOUT = "16";
1180
    const PAGE_ALL_LANGUAGES = "17";
1181
    const PAGE_LANGUAGE_DETAIL = "18";
1182
    const PAGE_CUSTOMIZE = "19";
1183
    const PAGE_ALL_PUBLISHERS = "20";
1184
    const PAGE_PUBLISHER_DETAIL = "21";
1185
    const PAGE_ALL_RATINGS = "22";
1186
    const PAGE_RATING_DETAIL = "23";
1187
1188
    const COMPATIBILITY_XML_ALDIKO = "aldiko";
1189
1190
    private static $db = NULL;
1191
1192 144
    public static function isMultipleDatabaseEnabled () {
1193 144
        global $config;
1194 144
        return is_array ($config['calibre_directory']);
1195
    }
1196
1197 49
    public static function useAbsolutePath () {
1198 49
        global $config;
1199 49
        $path = self::getDbDirectory();
1200 49
        return preg_match ('/^\//', $path) || // Linux /
1201 49
               preg_match ('/^\w\:/', $path); // Windows X:
1202
    }
1203
1204 56
    public static function noDatabaseSelected () {
1205 56
        return self::isMultipleDatabaseEnabled () && is_null (GetUrlParam (DB));
1206
    }
1207
1208 4
    public static function getDbList () {
1209 4
        global $config;
1210 4
        if (self::isMultipleDatabaseEnabled ()) {
1211 4
            return $config['calibre_directory'];
1212
        } else {
1213 1
            return array ("" => $config['calibre_directory']);
1214
        }
1215
    }
1216
1217 5
    public static function getDbNameList () {
1218 5
        global $config;
1219 5
        if (self::isMultipleDatabaseEnabled ()) {
1220 5
            return array_keys ($config['calibre_directory']);
1221
        } else {
1222
            return array ("");
1223
        }
1224
    }
1225
1226 1
    public static function getDbName ($database = NULL) {
1227 1
        global $config;
1228 1
        if (self::isMultipleDatabaseEnabled ()) {
1229 1
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1230 1
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1231
                self::error ($database);
1232
            }
1233 1
            $array = array_keys ($config['calibre_directory']);
1234 1
            return  $array[$database];
1235
        }
1236
        return "";
1237
    }
1238
1239 126
    public static function getDbDirectory ($database = NULL) {
1240 126
        global $config;
1241 126
        if (self::isMultipleDatabaseEnabled ()) {
1242 9
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1243 9
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1244
                self::error ($database);
1245
            }
1246 9
            $array = array_values ($config['calibre_directory']);
1247 9
            return  $array[$database];
1248
        }
1249 117
        return $config['calibre_directory'];
1250
    }
1251
1252
1253 98
    public static function getDbFileName ($database = NULL) {
1254 98
        return self::getDbDirectory ($database) .'metadata.db';
1255
    }
1256
1257 2
    private static function error ($database) {
1258 2
        if (php_sapi_name() != "cli") {
1259
            header("location: checkconfig.php?err=1");
1260
        }
1261 2
        throw new Exception("Database <{$database}> not found.");
1262
    }
1263
1264 159
    public static function getDb ($database = NULL) {
1265 159
        if (is_null (self::$db)) {
1266
            try {
1267 98
                if (is_readable (self::getDbFileName ($database))) {
1268 97
                    self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
1269 97
                    if (useNormAndUp ()) {
1270 7
                        self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1);
1271 7
                    }
1272 97
                } else {
1273 2
                    self::error ($database);
1274
                }
1275 98
            } catch (Exception $e) {
1276 2
                self::error ($database);
1277
            }
1278 97
        }
1279 158
        return self::$db;
1280
    }
1281
1282 4
    public static function checkDatabaseAvailability () {
1283 4
        if (self::noDatabaseSelected ()) {
1284 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...
1285 3
                self::getDb ($i);
1286 2
                self::clearDb ();
1287 2
            }
1288 1
        } else {
1289 1
            self::getDb ();
1290
        }
1291 2
        return true;
1292
    }
1293
1294 103
    public static function clearDb () {
1295 103
        self::$db = NULL;
1296 103
    }
1297
1298 24
    public static function executeQuerySingle ($query, $database = NULL) {
1299 24
        return self::getDb ($database)->query($query)->fetchColumn();
1300
    }
1301
1302 19
    public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL) {
1303 19
        if (!$numberOfString) {
1304 18
            $numberOfString = $table . ".alphabetical";
1305 18
        }
1306 19
        $count = self::executeQuerySingle ('select count(*) from ' . $table);
1307 19
        if ($count == 0) return NULL;
1308 19
        $entry = new Entry (localize($table . ".title"), $id,
1309 19
            str_format (localize($numberOfString, $count), $count), "text",
1310 19
            array ( new LinkNavigation ("?page=".$pageId)), "", $count);
1311 19
        return $entry;
1312
    }
1313
1314 35
    public static function getEntryArrayWithBookNumber ($query, $columns, $params, $category) {
1315
        /* @var $result PDOStatement */
1316
1317 35
        list (, $result) = self::executeQuery ($query, $columns, "", $params, -1);
1318 35
        $entryArray = array();
1319 35
        while ($post = $result->fetchObject ())
1320
        {
1321
            /* @var $instance Author|Tag|Serie|Publisher */
1322
1323 25
            $instance = new $category ($post);
1324 25
            if (property_exists($post, "sort")) {
1325 17
                $title = $post->sort;
1326 17
            } else {
1327 8
                $title = $post->name;
1328
            }
1329 25
            array_push ($entryArray, new Entry ($title, $instance->getEntryId (),
1330 25
                str_format (localize("bookword", $post->count), $post->count), "text",
1331 25
                array ( new LinkNavigation ($instance->getUri ())), "", $post->count));
1332 25
        }
1333 35
        return $entryArray;
1334
    }
1335
1336 75
    public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL) {
1337 75
        $totalResult = -1;
1338
1339 75
        if (useNormAndUp ()) {
1340 7
            $query = preg_replace("/upper/", "normAndUp", $query);
1341 7
            $columns = preg_replace("/upper/", "normAndUp", $columns);
1342 7
        }
1343
1344 75
        if (is_null ($numberPerPage)) {
1345 73
            $numberPerPage = getCurrentOption ("max_item_per_page");
1346 73
        }
1347
1348 75
        if ($numberPerPage != -1 && $n != -1)
1349 75
        {
1350
            // First check total number of results
1351 28
            $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
1352 28
            $result->execute ($params);
1353 28
            $totalResult = $result->fetchColumn ();
1354
1355
            // Next modify the query and params
1356 28
            $query .= " limit ?, ?";
1357 28
            array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage);
1358 28
        }
1359
1360 75
        $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
1361 75
        $result->execute ($params);
1362 75
        return array ($totalResult, $result);
1363
    }
1364
1365
}
1366