Completed
Pull Request — master (#296)
by
unknown
13:28
created

PageQueryResult::searchByScope()   D

Complexity

Conditions 9
Paths 28

Size

Total Lines 37
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 32
nc 28
nop 2
dl 0
loc 37
ccs 28
cts 28
cp 1
crap 9
rs 4.909
c 0
b 0
f 0
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.1");
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 (isset($config ["cops_" . $option])) {
80 98
        return $config ["cops_" . $option];
81
    }
82
83
    return "";
84
}
85
86
function getCurrentCss () {
87 2
    return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css";
88
}
89
90
function getCurrentTemplate () {
91 4
    return getCurrentOption ("template");
92
}
93
94
function getUrlWithVersion ($url) {
95 69
    return $url . "?v=" . VERSION;
96
}
97
98
function xml2xhtml($xml) {
99 37
    return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', create_function('$m', '
100
        $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 37
    '), $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
function are_libxml_errors_ok ()
134
{
135 37
    $errors = libxml_get_errors();
136
137 37
    foreach ($errors as $error) {
138
        if ($error->code == 801) return false;
139 37
    }
140 37
    return true;
141
}
142
143
function html2xhtml ($html) {
144 37
    $doc = new DOMDocument();
145 37
    libxml_use_internal_errors(true);
146
147 37
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
148 37
                        $html  . '</body></html>'); // Load the HTML
149 37
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
150 37
    $output = xml2xhtml($output);
151 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)) {
152 37
        $output = $matches [1]; // Remove <html><body>
153 37
    }
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
    */
162
163 37
    if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
164
165 37
    libxml_use_internal_errors(false);
166 37
    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
 */
173
function str_format($format) {
0 ignored issues
show
Unused Code introduced by
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 116
    $args = func_get_args();
175 116
    $format = array_shift($args);
176
177 116
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
178 116
    $offset = 0;
179 116
    foreach ($matches[1] as $data) {
180 116
        $i = $data[0];
181 116
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
182 116
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
183 116
    }
184
185 116
    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
 */
193
function getAcceptLanguages() {
194 16
    $langs = array();
195
196 16
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
197
        // break up string into pieces (languages and q factors)
198 16
        $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
199 16
        if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) {
200
            // Special fix for IE11 which send fr-FR and nothing else
201 3
            $accept = $accept . "," . $matches[1] . ";q=0.8";
202 3
        }
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
205 16
        if (count($lang_parse[1])) {
206 16
            $langs = array();
207 16
            foreach ($lang_parse[1] as $lang) {
208
                // Format the language code (not standard among browsers)
209 16
                if (strlen($lang) == 5) {
210 11
                    $lang = str_replace("-", "_", $lang);
211 11
                    $splitted = preg_split("/_/", $lang);
212 11
                    $lang = $splitted[0] . "_" . strtoupper($splitted[1]);
213 11
                }
214 16
                array_push($langs, $lang);
215 16
            }
216
            // create a list like "en" => 0.8
217 16
            $langs = array_combine($langs, $lang_parse[4]);
218
219
            // set default to 1 for any without q factor
220 16
            foreach ($langs as $lang => $val) {
221 16
                if ($val === '') $langs[$lang] = 1;
222 16
            }
223
224
            // sort list based on value
225 16
            arsort($langs, SORT_NUMERIC);
226 16
        }
227 16
    }
228
229 16
    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
 */
236
function getLangAndTranslationFile() {
237 17
    global $config;
238 17
    $langs = array();
239 17
    $lang = "en";
240 17
    if (!empty($config['cops_language'])) {
241
        $lang = $config['cops_language'];
242
    }
243 17
    elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
244 16
        $langs = getAcceptLanguages();
245 16
    }
246
    //echo var_dump($langs);
247 17
    $lang_file = NULL;
248 17
    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 16
            $lang_file = $temp_file;
253 16
            break;
254
        }
255 17
    }
256 17
    if (empty ($lang_file)) {
257 3
        $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
258 3
    }
259 17
    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
 */
266
function localize($phrase, $count=-1, $reset=false) {
267 136
    global $config;
268 136
    if ($count == 0)
269 136
        $phrase .= ".none";
270 136
    if ($count == 1)
271 136
        $phrase .= ".one";
272 136
    if ($count > 1)
273 136
        $phrase .= ".many";
274
275
    /* Static keyword is used to ensure the file is loaded only once */
276 136
    static $translations = NULL;
277 136
    if ($reset) {
278 16
        $translations = NULL;
279 16
    }
280
    /* If no instance of $translations has occured load the language file */
281 136
    if (is_null($translations)) {
282 17
        $lang_file_en = NULL;
283 17
        list ($lang, $lang_file) = getLangAndTranslationFile();
284 17
        if ($lang != "en") {
285 1
            $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
286 1
        }
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 17
        $translations = json_decode($lang_file_content, true);
291
292
        /* Clean the array of all unfinished translations */
293 17
        foreach (array_keys ($translations) as $key) {
294 17
            if (preg_match ("/^##TODO##/", $key)) {
295
                unset ($translations [$key]);
296
            }
297 17
        }
298
        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 17
        {
300 1
            $lang_file_content = file_get_contents($lang_file_en);
301 1
            $translations_en = json_decode($lang_file_content, true);
302 1
            $translations = array_merge ($translations_en, $translations);
303 1
        }
304 17
    }
305 136
    if (array_key_exists ($phrase, $translations)) {
306 136
        return $translations[$phrase];
307
    }
308 3
    return $phrase;
309
}
310
311
function addURLParameter($urlParams, $paramName, $paramValue) {
312 61
    if (empty ($urlParams)) {
313 51
        $urlParams = "";
314 51
    }
315 61
    $start = "";
316 61
    if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
317 15
        $start = "?";
318 15
        $urlParams = $matches[1];
319 15
    }
320 61
    $params = array();
321 61
    parse_str($urlParams, $params);
322 61
    if (empty ($paramValue) && $paramValue != 0) {
323
        unset ($params[$paramName]);
324
    } else {
325 61
        $params[$paramName] = $paramValue;
326
    }
327 61
    return $start . http_build_query($params);
328
}
329
330
function useNormAndUp () {
331 144
    global $config;
332 144
    return $config ['cops_normalized_search'] == "1";
333
}
334
335
function normalizeUtf8String( $s) {
336 8
    include_once 'transliteration.php';
337 8
    return _transliteration_process($s);
338
}
339
340
function normAndUp ($s) {
341 7
    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
    public $activeFacet;
358
359 117
    public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
360 117
        $this->href = $phref;
361 117
        $this->type = $ptype;
362 117
        $this->rel = $prel;
363 117
        $this->title = $ptitle;
364 117
        $this->facetGroup = $pfacetGroup;
365 117
        $this->activeFacet = $pactiveFacet;
366 117
    }
367
368 11
    public function hrefXhtml () {
369 11
        return $this->href;
370
    }
371
372 116
    public function getScriptName() {
373 116
        $parts = explode('/', $_SERVER["SCRIPT_NAME"]);
374 116
        return $parts[count($parts) - 1];
375
    }
376
}
377
378
class LinkNavigation extends Link
379
{
380 116
    public function __construct($phref, $prel = NULL, $ptitle = NULL) {
381 116
        parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
382 116
        if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
383 116
        if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
384 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...
385
            $this->href = "index.php" . $this->href;
386
        } else {
387 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...
388
        }
389 116
    }
390
}
391
392
class LinkFacet extends Link
393
{
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 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...
398 1
    }
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
        Publishdate::ALL_PUBLISHDATES_ID => 'images/publishdate.png'
425
    );
426
427
    public function getUpdatedTime () {
428
        if (!is_null ($this->localUpdated)) {
429
            return date (DATE_ATOM, $this->localUpdated);
430
        }
431
        if (is_null (self::$updated)) {
432
            self::$updated = time();
433
        }
434
        return date (DATE_ATOM, self::$updated);
435
    }
436 7
437 7
    public function getNavLink () {
438
        foreach ($this->linkArray as $link) {
439
            /* @var $link LinkNavigation */
440 7
441
            if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
442 7
443
            return $link->hrefXhtml ();
444
        }
445
        return "#";
446
    }
447 109
448 109
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) {
449 109
        global $config;
450 109
        $this->title = $ptitle;
451 109
        $this->id = $pid;
452 109
        $this->content = $pcontent;
453 109
        $this->contentType = $pcontentType;
454 109
        $this->linkArray = $plinkArray;
455 109
        $this->className = $pclass;
456
        $this->numberOfElement = $pcount;
457 109
458 109
        if ($config['cops_show_icons'] == 1)
459 109
        {
460
            foreach (self::$icons as $reg => $image)
461 109
            {
462 69
                if (preg_match ("/" . $reg . "/", $pid)) {
463 69
                    array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE));
464
                    break;
465 109
                }
466 109
            }
467
        }
468 109
469 109
        if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":", $this->id);
470
    }
471
}
472
473
class EntryBook extends Entry
474
{
475
    public $book;
476
477
    /**
478
     * EntryBook constructor.
479
     * @param string $ptitle
480
     * @param integer $pid
481
     * @param string $pcontent
482
     * @param string $pcontentType
483
     * @param array $plinkArray
484
     * @param Book $pbook
485 41
     */
486 41
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) {
487 41
        parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray);
488 41
        $this->book = $pbook;
489 41
        $this->localUpdated = $pbook->timestamp;
490
    }
491
492
    public function getCoverThumbnail () {
493
        foreach ($this->linkArray as $link) {
494
            /* @var $link LinkNavigation */
495
496
            if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
497
                return $link->hrefXhtml ();
498
        }
499
        return null;
500
    }
501
502
    public function getCover () {
503
        foreach ($this->linkArray as $link) {
504
            /* @var $link LinkNavigation */
505
506
            if ($link->rel == Link::OPDS_IMAGE_TYPE)
507
                return $link->hrefXhtml ();
508
        }
509
        return null;
510
    }
511
}
512
513
class Page
514
{
515
    public $title;
516
    public $subtitle = "";
517
    public $authorName = "";
518
    public $authorUri = "";
519
    public $authorEmail = "";
520
    public $idPage;
521
    public $idGet;
522
    public $query;
523
    public $favicon;
524
    public $n;
525
    public $book;
526
    public $totalNumber = -1;
527
528
    /* @var Entry[] */
529
    public $entryArray = array();
530 102
531
    public static function getPage ($pageId, $id, $query, $n)
532
    {
533 102
        switch ($pageId) {
534 3
            case Base::PAGE_ALL_AUTHORS :
535 99
                return new PageAllAuthors ($id, $query, $n);
536 1
            case Base::PAGE_AUTHORS_FIRST_LETTER :
537 98
                return new PageAllAuthorsLetter ($id, $query, $n);
538 7
            case Base::PAGE_AUTHOR_DETAIL :
539 91
                return new PageAuthorDetail ($id, $query, $n);
540 2
            case Base::PAGE_ALL_TAGS :
541 89
                return new PageAllTags ($id, $query, $n);
542 1
            case Base::PAGE_TAG_DETAIL :
543 88
                return new PageTagDetail ($id, $query, $n);
544 2
            case Base::PAGE_ALL_LANGUAGES :
545 86
                return new PageAllLanguages ($id, $query, $n);
546 1
            case Base::PAGE_LANGUAGE_DETAIL :
547 85
                return new PageLanguageDetail ($id, $query, $n);
548 12
            case Base::PAGE_ALL_CUSTOMS :
549 73
                return new PageAllCustoms ($id, $query, $n);
550 4
            case Base::PAGE_CUSTOM_DETAIL :
551 69
                return new PageCustomDetail ($id, $query, $n);
552 1
            case Base::PAGE_ALL_RATINGS :
553 68
                return new PageAllRating ($id, $query, $n);
554 1
            case Base::PAGE_RATING_DETAIL :
555 67
                return new PageRatingDetail ($id, $query, $n);
556 2
            case Base::PAGE_ALL_SERIES :
557 65
                return new PageAllSeries ($id, $query, $n);
558 3
            case Base::PAGE_ALL_BOOKS :
559 62
                return new PageAllBooks ($id, $query, $n);
560 1
            case Base::PAGE_ALL_BOOKS_LETTER:
561 61
                return new PageAllBooksLetter ($id, $query, $n);
562 4
            case Base::PAGE_ALL_RECENT_BOOKS :
563 57
                return new PageRecentBooks ($id, $query, $n);
564 1
            case Base::PAGE_SERIE_DETAIL :
565 56
                return new PageSerieDetail ($id, $query, $n);
566 31
            case Base::PAGE_OPENSEARCH_QUERY :
567 25
                return new PageQueryResult ($id, $query, $n);
568 1
            case Base::PAGE_BOOK_DETAIL :
569 24
                return new PageBookDetail ($id, $query, $n);
570 2
            case Base::PAGE_ALL_PUBLISHERS:
571 22
                return new PageAllPublishers ($id, $query, $n);
572 1
            case Base::PAGE_PUBLISHER_DETAIL :
573 21
                return new PagePublisherDetail ($id, $query, $n);
574
            case Base::PAGE_ALL_PUBLISHDATES:
575 21
                return new PageAllPublishdates ($id, $query, $n);
576
            case Base::PAGE_PUBLISHDATE_YEAR :
577 21
                return new PagePublishdateYear($id, $query, $n);
578 21
            case Base::PAGE_PUBLISHDATE_MONTH :
579 21
                return new PagePublishdateMonth ($id, $query, $n);
580 21
            case Base::PAGE_ABOUT :
581 21
                return new PageAbout ($id, $query, $n);
582
            case Base::PAGE_CUSTOMIZE :
583
                return new PageCustomize ($id, $query, $n);
584 102
            default:
585 102
                $page = new Page ($id, $query, $n);
586
                $page->idPage = "cops:catalog";
587 102
                return $page;
588 102
        }
589 102
    }
590 102
591 102
    public function __construct($pid, $pquery, $pn) {
592 102
        global $config;
593 102
594 102
        $this->idGet = $pid;
595
        $this->query = $pquery;
596 21
        $this->n = $pn;
597
        $this->favicon = $config['cops_icon'];
598 21
        $this->authorName = empty($config['cops_author_name']) ? utf8_encode('Sébastien Lucas') : $config['cops_author_name'];
599 21
        $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri'];
600 21
        $this->authorEmail = empty($config['cops_author_email']) ? '[email protected]' : $config['cops_author_email'];
601 21
    }
602 2
603 2
    public function InitializeContent ()
604 2
    {
605 2
        global $config;
606 2
        $this->title = $config['cops_title_default'];
607 2
        $this->subtitle = $config['cops_subtitle_default'];
608 2
        if (Base::noDatabaseSelected ()) {
609 2
            $i = 0;
610 2
            foreach (Base::getDbNameList () as $key) {
611 2
                $nBooks = Book::getBookCount ($i);
612 19
                array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog",
613 18
                                        str_format (localize ("bookword", $nBooks), $nBooks), "text",
614 18
                                        array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks));
615 19
                $i++;
616 18
                Base::clearDb ();
617 18
            }
618 18
        } else {
619 19
            if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) {
620 18
                array_push ($this->entryArray, Author::getCount());
621 18
            }
622 18
            if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) {
623 19
                $series = Serie::getCount();
624 18
                if (!is_null ($series)) array_push ($this->entryArray, $series);
625 18
            }
626 18
            if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) {
627 19
                $publisher = Publisher::getCount();
628 19
                if (!is_null ($publisher)) array_push ($this->entryArray, $publisher);
629 19
            }
630 19
            if (!in_array (PageQueryResult::SCOPE_PUBLISHDATE, getCurrentOption ('ignored_categories'))) {
631 19
                $publishdates = Publishdate::getCount();
632 18
                if (!is_null ($publishdates)) array_push ($this->entryArray, $publishdates);
633 18
            }
634 18
            if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) {
635 19
                $tags = Tag::getCount();
636 15
                if (!is_null ($tags)) array_push ($this->entryArray, $tags);
637 15
            }
638 14
            if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) {
639 14
                $rating = Rating::getCount();
640 19
                if (!is_null ($rating)) array_push ($this->entryArray, $rating);
641 19
            }
642
            if (!in_array ("language", getCurrentOption ('ignored_categories'))) {
643 19
                $languages = Language::getCount();
644
                if (!is_null ($languages)) array_push ($this->entryArray, $languages);
645 21
            }
646
            foreach ($config['cops_calibre_custom_column'] as $lookup) {
647 17
                $customColumn = CustomColumnType::createByLookup($lookup);
648
                if (!is_null ($customColumn) && $customColumn->isSearchable()) {
649 17
                    array_push ($this->entryArray, $customColumn->getCount());
650 17
                }
651 17
            }
652
            $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...
653
654 2
            if (Base::isMultipleDatabaseEnabled ()) $this->title =  Base::getDbName ();
655
        }
656 2
    }
657 2
658 1
    public function isPaginated ()
659
    {
660 1
        return (getCurrentOption ("max_item_per_page") != -1 &&
661
                $this->totalNumber != -1 &&
662
                $this->totalNumber > getCurrentOption ("max_item_per_page"));
663 2
    }
664
665 2
    public function getNextLink ()
666 2
    {
667 1
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
668
        if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) {
669 2
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate"));
670
        }
671
        return NULL;
672 2
    }
673
674 2
    public function getPrevLink ()
675
    {
676
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
677 70
        if ($this->n > 1) {
678
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate"));
679 70
        }
680 68
        return NULL;
681 46
    }
682
683
    public function getMaxPage ()
684
    {
685
        return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page"));
686
    }
687 3
688
    public function containsBook ()
689 3
    {
690 3
        if (count ($this->entryArray) == 0) return false;
691 2
        if (get_class ($this->entryArray [0]) == "EntryBook") return true;
692 2
        return false;
693
    }
694 1
}
695
696 3
class PageAllAuthors extends Page
697 3
{
698
    public function InitializeContent ()
699
    {
700
        $this->title = localize("authors.title");
701
        if (getCurrentOption ("author_split_first_letter") == 1) {
702 1
            $this->entryArray = Author::getAllAuthorsByFirstLetter();
703
        }
704 1
        else {
705 1
            $this->entryArray = Author::getAllAuthors();
706 1
        }
707 1
        $this->idPage = Author::ALL_AUTHORS_ID;
708
    }
709
}
710
711
class PageAllAuthorsLetter extends Page
712 7
{
713
    public function InitializeContent ()
714 7
    {
715 7
        $this->idPage = Author::getEntryIdByLetter ($this->idGet);
716 7
        $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet);
717 7
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet);
718 7
    }
719
}
720
721
class PageAuthorDetail extends Page
722
{
723 2
    public function InitializeContent ()
724
    {
725 2
        $author = Author::getAuthorById ($this->idGet);
726 2
        $this->idPage = $author->getEntryId ();
727 2
        $this->title = $author->name;
728 2
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n);
729
    }
730
}
731
732
class PageAllPublishers extends Page
733 1
{
734
    public function InitializeContent ()
735 1
    {
736 1
        $this->title = localize("publishers.title");
737 1
        $this->entryArray = Publisher::getAllPublishers();
738 1
        $this->idPage = Publisher::ALL_PUBLISHERS_ID;
739 1
    }
740
}
741
742
class PagePublisherDetail extends Page
743
{
744 2
    public function InitializeContent ()
745
    {
746 2
        $publisher = Publisher::getPublisherById ($this->idGet);
747 2
        $this->title = $publisher->name;
748 2
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n);
749 2
        $this->idPage = $publisher->getEntryId ();
750
    }
751
}
752
753
class PageAllPublishdates extends Page
754 2
{
755
    public function InitializeContent ()
756 2
    {
757 2
        $this->title = localize("pubdate.title");
758 2
        $this->entryArray = Publishdate::getAllPublishdates();
759 2
        $this->idPage = Publishdate::ALL_PUBLISHDATES_ID;
760
    }
761
}
762
763
class PagePublishdateYear extends Page
764 4
{
765
    public function InitializeContent ()
766 4
    {
767 4
        $publishdateYear = $this->idGet;
0 ignored issues
show
Unused Code introduced by
$publishdateYear is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
768 4
        $this->title = $this->idGet;
769 4
        $this->entryArray = PublishdateYear::getAllPublishdateMonth ($this->idGet);
770 4
        $this->idPage = PublishdateYear::PUBLISHDATE_YEAR_ID;
771 4
    }
772
}
773
774
class PagePublishdateMonth extends Page
775
{
776 12
    public function InitializeContent ()
777
    {
778 12
        $publishdateMonth = PublishdateYear::getPublishdateMonth ($this->idGet);
779 12
        $this->title = $this->idGet;
780
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublishdate ($this->idGet, $this->n);
781 12
        $this->idPage = $publishdateMonth->getEntryId ();
782 12
    }
783 12
}
784 12
785
class PageAllTags extends Page
786
{
787
    public function InitializeContent ()
788
    {
789 1
        $this->title = localize("tags.title");
790
        $this->entryArray = Tag::getAllTags();
791 1
        $this->idPage = Tag::ALL_TAGS_ID;
792 1
    }
793 1
}
794 1
795 1
class PageAllLanguages extends Page
796
{
797
    public function InitializeContent ()
798
    {
799
        $this->title = localize("languages.title");
800 1
        $this->entryArray = Language::getAllLanguages();
801
        $this->idPage = Language::ALL_LANGUAGES_ID;
802 1
    }
803 1
}
804 1
805 1
class PageCustomDetail extends Page
806 1
{
807
    public function InitializeContent ()
808
    {
809
        $customId = getURLParam ("custom", NULL);
810
        $custom = CustomColumn::createCustom ($customId, $this->idGet);
811 2
        $this->idPage = $custom->getEntryId ();
812
        $this->title = $custom->value;
813 2
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($custom, $this->idGet, $this->n);
814 2
    }
815 2
}
816 2
817
class PageAllCustoms extends Page
818
{
819
    public function InitializeContent ()
820
    {
821 1
        $customId = getURLParam ("custom", NULL);
822
        $columnType = CustomColumnType::createByCustomID($customId);
823 1
        
824 1
        $this->title = $columnType->getTitle();
825 1
        $this->entryArray = $columnType->getAllCustomValues();
826 1
        $this->idPage = $columnType->getAllCustomsId();
827 1
    }
828
}
829
830
class PageTagDetail extends Page
831
{
832 1
    public function InitializeContent ()
833
    {
834 1
        $tag = Tag::getTagById ($this->idGet);
835 1
        $this->idPage = $tag->getEntryId ();
836 1
        $this->title = $tag->name;
837 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n);
838
    }
839
}
840
841
class PageLanguageDetail extends Page
842 1
{
843
    public function InitializeContent ()
844 1
    {
845 1
        $language = Language::getLanguageById ($this->idGet);
846 1
        $this->idPage = $language->getEntryId ();
847 1
        $this->title = $language->lang_code;
848 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n);
849
    }
850
}
851
852
class PageAllSeries extends Page
853 3
{
854
    public function InitializeContent ()
855 3
    {
856 3
        $this->title = localize("series.title");
857 2
        $this->entryArray = Serie::getAllSeries();
858 2
        $this->idPage = Serie::ALL_SERIES_ID;
859
    }
860 1
}
861
862 3
class PageSerieDetail extends Page
863 3
{
864
    public function InitializeContent ()
865
    {
866
        $serie = Serie::getSerieById ($this->idGet);
867
        $this->title = $serie->name;
868 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n);
869
        $this->idPage = $serie->getEntryId ();
870 1
    }
871 1
}
872
873 1
class PageAllRating extends Page
874 1
{
875 1
    public function InitializeContent ()
876
    {
877 1
        $this->title = localize("ratings.title");
878 1
        $this->entryArray = Rating::getAllRatings();
879
        $this->idPage = Rating::ALL_RATING_ID;
880
    }
881
}
882
883 4
class PageRatingDetail extends Page
884
{
885 4
    public function InitializeContent ()
886 4
    {
887 4
        $rating = Rating::getRatingById ($this->idGet);
888 4
        $this->idPage = $rating->getEntryId ();
889
        $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2);
890
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n);
891
    }
892
}
893
894
class PageAllBooks extends Page
895
{
896
    public function InitializeContent ()
897
    {
898
        $this->title = localize ("allbooks.title");
899
        if (getCurrentOption ("titles_split_first_letter") == 1) {
900 24
            $this->entryArray = Book::getAllBooks();
901 24
        }
902
        else {
903
            list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n);
904 29
        }
905 29
        $this->idPage = Book::ALL_BOOKS_ID;
906 29
    }
907 29
}
908 29
909 7
class PageAllBooksLetter extends Page
910 7
{
911 29
    public function InitializeContent ()
912 22
    {
913 22
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n);
914 22
        $this->idPage = Book::getEntryIdByLetter ($this->idGet);
915
916 29
        $count = $this->totalNumber;
917 23
        if ($count == -1)
918 23
            $count = count ($this->entryArray);
919 28
920 23
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet);
921 23
    }
922 25
}
923 22
924 22
class PageRecentBooks extends Page
925 24
{
926 23
    public function InitializeContent ()
927 23
    {
928 23
        $this->title = localize ("recent.title");
929 23
        $this->idPage = Book::ALL_RECENT_BOOKS_ID;
930 23
        list ($this->entryArray, $this->totalNumber) = Book::getAllRecentBooks ($this->n);
931
    }
932
}
933
934
class PageQueryResult extends Page
935
{
936 29
    const SCOPE_TAG = "tag";
937
    const SCOPE_RATING = "rating";
938
    const SCOPE_SERIES = "series";
939 22
    const SCOPE_AUTHOR = "author";
940 22
    const SCOPE_BOOK = "book";
941 22
    const SCOPE_PUBLISHER = "publisher";
942 22
    const SCOPE_PUBLISHDATE = "publishdate";
943 22
944 22
    private function useTypeahead () {
945 22
        return !is_null (getURLParam ("search"));
946
    }
947 22
948 1
    private function searchByScope ($scope, $limit = FALSE) {
949 1
        $n = $this->n;
950 1
        $numberPerPage = NULL;
951 22
        $queryNormedAndUp = trim($this->query);
952 22
        if (useNormAndUp ()) {
953 1
            $queryNormedAndUp = normAndUp ($this->query);
954 1
        }
955 1
        if ($limit) {
956 1
            $n = 1;
957 1
            $numberPerPage = 5;
958 22
        }
959 22
        switch ($scope) {
960 22
            case self::SCOPE_BOOK :
961 22
                $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, $numberPerPage);
962 22
                break;
963 22
            case self::SCOPE_AUTHOR :
964 3
                $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp);
965
                break;
966 22
            case self::SCOPE_SERIES :
967
                $array = Serie::getAllSeriesByQuery ($queryNormedAndUp);
968 22
                break;
969 22
            case self::SCOPE_TAG :
970 22
                $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage);
971 22
                break;
972 22
            case self::SCOPE_PUBLISHER :
973 22
                $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp);
974
                break;
975 22
            case self::SCOPE_PUBLISHDATE :
976
                $array = Publishdate::getAllPublishdatesByQuery($queryNormedAndUp);
0 ignored issues
show
Bug introduced by
The method getAllPublishdatesByQuery() does not exist on Publishdate. Did you maybe mean getAllPublishdates()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
977
                break;
978
            default:
979
                $array = Book::getBooksByQuery (
980
                    array ("all" => "%" . $queryNormedAndUp . "%"), $n);
981
        }
982 21
983 21
        return $array;
984 21
    }
985 21
986 21
    public function doSearchByCategory () {
987 22
        $database = GetUrlParam (DB);
988 6
        $out = array ();
989 6
        $pagequery = Base::PAGE_OPENSEARCH_QUERY;
990 6
        $dbArray = array ("");
991 6
        $d = $database;
992 6
        $query = $this->query;
993 6
        // Special case when no databases were chosen, we search on all databases
994 22
        if (Base::noDatabaseSelected ()) {
995 22
            $dbArray = Base::getDbNameList ();
996 22
            $d = 0;
997 1
        }
998 1
        foreach ($dbArray as $key) {
999 22
            if (Base::noDatabaseSelected ()) {
1000 22
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$d}",
1001
                                        " ", "text",
1002
                                        array ( new LinkNavigation ("?" . DB . "={$d}")), "tt-header"));
1003 31
                Base::getDb ($d);
1004
            }
1005 31
            foreach (array (PageQueryResult::SCOPE_BOOK,
1006 31
                            PageQueryResult::SCOPE_AUTHOR,
1007 24
                            PageQueryResult::SCOPE_SERIES,
1008 24
                            PageQueryResult::SCOPE_TAG,
1009
                            PageQueryResult::SCOPE_PUBLISHER,
1010
                            PageQueryResult::SCOPE_PUBLISHDATE) as $key) {
1011
                if (in_array($key, getCurrentOption ('ignored_categories'))) {
1012
                    continue;
1013
                }
1014
                $array = $this->searchByScope ($key, TRUE);
1015 7
1016
                $i = 0;
1017
                if (count ($array) == 2 && is_array ($array [0])) {
1018 31
                    $total = $array [1];
1019
                    $array = $array [0];
1020
                } else {
1021 31
                    $total = count($array);
1022 2
                }
1023 2
                if ($total > 0) {
1024 2
                    // Comment to help the perl i18n script
1025 2
                    // str_format (localize("bookword", count($array))
1026 2
                    // str_format (localize("authorword", count($array))
1027 2
                    // str_format (localize("seriesword", count($array))
1028 2
                    // str_format (localize("tagword", count($array))
1029 2
                    // str_format (localize("publisherword", count($array))
1030 2
                    array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}",
1031 2
                                        str_format (localize("{$key}word", $total), $total), "text",
1032
                                        array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&scope={$key}")),
1033 29
                                        Base::noDatabaseSelected () ? "" : "tt-header", $total));
1034 22
                }
1035 22
                if (!Base::noDatabaseSelected () && $this->useTypeahead ()) {
1036
                    foreach ($array as $entry) {
1037
                        array_push ($this->entryArray, $entry);
1038 7
                        $i++;
1039 7
                        if ($i > 4) { break; };
1040 2
                    }
1041 2
                }
1042 5
            }
1043
            $d++;
1044 7
            if (Base::noDatabaseSelected ()) {
1045
                Base::clearDb ();
1046
            }
1047
        }
1048
        return $out;
1049 1
    }
1050
1051 1
    public function InitializeContent ()
1052 1
    {
1053 1
        $scope = getURLParam ("scope");
1054
        if (empty ($scope)) {
1055
            $this->title = str_format (localize ("search.result"), $this->query);
1056
        } else {
1057
            // Comment to help the perl i18n script
1058
            // str_format (localize ("search.result.author"), $this->query)
1059
            // str_format (localize ("search.result.tag"), $this->query)
1060
            // str_format (localize ("search.result.series"), $this->query)
1061
            // str_format (localize ("search.result.book"), $this->query)
1062
            // str_format (localize ("search.result.publisher"), $this->query)
1063
            $this->title = str_format (localize ("search.result.{$scope}"), $this->query);
1064
        }
1065
1066
        $crit = "%" . $this->query . "%";
1067
1068
        // Special case when we are doing a search and no database is selected
1069
        if (Base::noDatabaseSelected () && !$this->useTypeahead ()) {
1070
            $i = 0;
1071
            foreach (Base::getDbNameList () as $key) {
1072
                Base::clearDb ();
1073
                list ($array, $totalNumber) = Book::getBooksByQuery (array ("all" => $crit), 1, $i, 1);
0 ignored issues
show
Unused Code introduced by
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...
1074
                array_push ($this->entryArray, new Entry ($key, DB . ":query:{$i}",
1075
                                        str_format (localize ("bookword", $totalNumber), $totalNumber), "text",
1076
                                        array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber));
1077
                $i++;
1078
            }
1079
            return;
1080
        }
1081
        if (empty ($scope)) {
1082
            $this->doSearchByCategory ();
1083
            return;
1084
        }
1085
1086
        $array = $this->searchByScope ($scope);
1087
        if (count ($array) == 2 && is_array ($array [0])) {
1088
            list ($this->entryArray, $this->totalNumber) = $array;
1089
        } else {
1090
            $this->entryArray = $array;
1091
        }
1092
    }
1093
}
1094
1095
class PageBookDetail extends Page
1096
{
1097
    public function InitializeContent ()
1098
    {
1099
        $this->book = Book::getBookById ($this->idGet);
1100
        $this->title = $this->book->title;
1101
    }
1102
}
1103
1104
class PageAbout extends Page
1105
{
1106
    public function InitializeContent ()
1107
    {
1108
        $this->title = localize ("about.title");
1109
    }
1110
}
1111
1112
class PageCustomize extends Page
1113
{
1114
    private function isChecked ($key, $testedValue = 1) {
1115
        $value = getCurrentOption ($key);
1116
        if (is_array ($value)) {
1117
            if (in_array ($testedValue, $value)) {
1118
                return "checked='checked'";
1119
            }
1120
        } else {
1121
            if ($value == $testedValue) {
1122
                return "checked='checked'";
1123
            }
1124
        }
1125
        return "";
1126
    }
1127
1128
    private function isSelected ($key, $value) {
1129
        if (getCurrentOption ($key) == $value) {
1130
            return "selected='selected'";
1131
        }
1132
        return "";
1133
    }
1134
1135
    private function getStyleList () {
1136
        $result = array ();
1137
        foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) {
1138
            if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) {
1139
                array_push ($result, $m [1]);
1140
            }
1141
        }
1142
        return $result;
1143
    }
1144
1145
    public function InitializeContent ()
1146
    {
1147
        $this->title = localize ("customize.title");
1148
        $this->entryArray = array ();
1149
1150
        $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR,
1151
                                   PageQueryResult::SCOPE_TAG,
1152
                                   PageQueryResult::SCOPE_SERIES,
1153
                                   PageQueryResult::SCOPE_PUBLISHER,
1154
                                   PageQueryResult::SCOPE_PUBLISHDATE,
1155
                                   PageQueryResult::SCOPE_RATING,
1156
                                   "language");
1157
1158
        $content = "";
1159
        array_push ($this->entryArray, new Entry ("Template", "",
1160
                                        "<span style='cursor: pointer;' onclick='$.cookie(\"template\", \"bootstrap\", { expires: 365 });window.location=$(\".headleft\").attr(\"href\");'>Click to switch to Bootstrap</span>", "text",
1161
                                        array ()));
1162
        if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) {
1163
            $content .= '<select id="style" onchange="updateCookie (this);">';
1164
            foreach ($this-> getStyleList () as $filename) {
1165
                $content .= "<option value='{$filename}' " . $this->isSelected ("style", $filename) . ">{$filename}</option>";
1166
            }
1167
            $content .= '</select>';
1168
        } else {
1169
            foreach ($this-> getStyleList () as $filename) {
1170
                $content .= "<input type='radio' onchange='updateCookieFromCheckbox (this);' id='style-{$filename}' name='style' value='{$filename}' " . $this->isChecked ("style", $filename) . " /><label for='style-{$filename}'> {$filename} </label>";
1171
            }
1172
        }
1173
        array_push ($this->entryArray, new Entry (localize ("customize.style"), "",
1174
                                        $content, "text",
1175
                                        array ()));
1176
        if (!useServerSideRendering ()) {
1177
            $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="use_fancyapps" ' . $this->isChecked ("use_fancyapps") . ' />';
1178
            array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "",
1179
                                            $content, "text",
1180
                                            array ()));
1181
        }
1182
        $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]+$" />';
1183
        array_push ($this->entryArray, new Entry (localize ("customize.paging"), "",
1184
                                        $content, "text",
1185
                                        array ()));
1186
        $content = '<input type="text" onchange="updateCookie (this);" id="email" value="' . getCurrentOption ("email") . '" />';
1187
        array_push ($this->entryArray, new Entry (localize ("customize.email"), "",
1188 144
                                        $content, "text",
1189 144
                                        array ()));
1190 144
        $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="html_tag_filter" ' . $this->isChecked ("html_tag_filter") . ' />';
1191
        array_push ($this->entryArray, new Entry (localize ("customize.filter"), "",
1192
                                        $content, "text",
1193 49
                                        array ()));
1194 49
        $content = "";
1195 49
        foreach ($ignoredBaseArray as $key) {
1196 49
            $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s");
1197 49
            $content .=  '<input type="checkbox" name="ignored_categories[]" onchange="updateCookieFromCheckboxGroup (this);" id="ignored_categories_' . $key . '" ' . $this->isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . '</input> ';
1198
        }
1199
1200 56
        array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "",
1201 56
                                        $content, "text",
1202
                                        array ()));
1203
    }
1204 4
}
1205 4
1206 4
abstract class Base
1207 4
{
1208
    const PAGE_INDEX = "index";
1209 1
    const PAGE_ALL_AUTHORS = "1";
1210
    const PAGE_AUTHORS_FIRST_LETTER = "2";
1211
    const PAGE_AUTHOR_DETAIL = "3";
1212
    const PAGE_ALL_BOOKS = "4";
1213 5
    const PAGE_ALL_BOOKS_LETTER = "5";
1214 5
    const PAGE_ALL_SERIES = "6";
1215 5
    const PAGE_SERIE_DETAIL = "7";
1216 5
    const PAGE_OPENSEARCH = "8";
1217
    const PAGE_OPENSEARCH_QUERY = "9";
1218
    const PAGE_ALL_RECENT_BOOKS = "10";
1219
    const PAGE_ALL_TAGS = "11";
1220
    const PAGE_TAG_DETAIL = "12";
1221
    const PAGE_BOOK_DETAIL = "13";
1222 1
    const PAGE_ALL_CUSTOMS = "14";
1223 1
    const PAGE_CUSTOM_DETAIL = "15";
1224 1
    const PAGE_ABOUT = "16";
1225 1
    const PAGE_ALL_LANGUAGES = "17";
1226 1
    const PAGE_LANGUAGE_DETAIL = "18";
1227
    const PAGE_CUSTOMIZE = "19";
1228
    const PAGE_ALL_PUBLISHERS = "20";
1229 1
    const PAGE_ALL_PUBLISHDATES = "24";
1230 1
    const PAGE_PUBLISHDATE_YEAR = "25";
1231
    const PAGE_PUBLISHDATE_MONTH = "26";
1232
    const PAGE_PUBLISHER_DETAIL = "21";
1233
    const PAGE_ALL_RATINGS = "22";
1234
    const PAGE_RATING_DETAIL = "23";
1235 126
1236 126
    const COMPATIBILITY_XML_ALDIKO = "aldiko";
1237 126
1238 9
    private static $db = NULL;
1239 9
1240
    public static function isMultipleDatabaseEnabled () {
1241
        global $config;
1242 9
        return is_array ($config['calibre_directory']);
1243 9
    }
1244
1245 117
    public static function useAbsolutePath () {
1246
        global $config;
1247
        $path = self::getDbDirectory();
1248
        return preg_match ('/^\//', $path) || // Linux /
1249 98
               preg_match ('/^\w\:/', $path); // Windows X:
1250 98
    }
1251
1252
    public static function noDatabaseSelected () {
1253 2
        return self::isMultipleDatabaseEnabled () && is_null (GetUrlParam (DB));
1254 2
    }
1255
1256
    public static function getDbList () {
1257 2
        global $config;
1258
        if (self::isMultipleDatabaseEnabled ()) {
1259
            return $config['calibre_directory'];
1260 159
        } else {
1261 159
            return array ("" => $config['calibre_directory']);
1262
        }
1263 98
    }
1264 97
1265 97
    public static function getDbNameList () {
1266 7
        global $config;
1267 7
        if (self::isMultipleDatabaseEnabled ()) {
1268 97
            return array_keys ($config['calibre_directory']);
1269 2
        } else {
1270
            return array ("");
1271 98
        }
1272 2
    }
1273
1274 97
    public static function getDbName ($database = NULL) {
1275 158
        global $config;
1276
        if (self::isMultipleDatabaseEnabled ()) {
1277
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1278 4
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1279 4
                self::error ($database);
1280 3
            }
1281 3
            $array = array_keys ($config['calibre_directory']);
1282 2
            return  $array[$database];
1283 2
        }
1284 1
        return "";
1285 1
    }
1286
1287 2
    public static function getDbDirectory ($database = NULL) {
1288
        global $config;
1289
        if (self::isMultipleDatabaseEnabled ()) {
1290 103
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1291 103
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1292 103
                self::error ($database);
1293
            }
1294 24
            $array = array_values ($config['calibre_directory']);
1295 24
            return  $array[$database];
1296
        }
1297
        return $config['calibre_directory'];
1298 19
    }
1299 19
1300 18
1301 18
    public static function getDbFileName ($database = NULL) {
1302 19
        return self::getDbDirectory ($database) .'metadata.db';
1303 19
    }
1304 19
1305 19
    private static function error ($database) {
1306 19
        if (php_sapi_name() != "cli") {
1307 19
            header("location: checkconfig.php?err=1");
1308
        }
1309
        throw new Exception("Database <{$database}> not found.");
1310 35
    }
1311
1312
    public static function getDb ($database = NULL) {
1313 35
        if (is_null (self::$db)) {
1314 35
            try {
1315 35
                if (is_readable (self::getDbFileName ($database))) {
1316
                    self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
1317
                    if (useNormAndUp ()) {
1318
                        self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1);
1319 25
                    }
1320 25
                } else {
1321 17
                    self::error ($database);
1322 17
                }
1323 8
            } catch (Exception $e) {
1324
                self::error ($database);
1325 25
            }
1326 25
        }
1327 25
        return self::$db;
1328 25
    }
1329 35
1330
    public static function checkDatabaseAvailability () {
1331
        if (self::noDatabaseSelected ()) {
1332 75
            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...
1333 75
                self::getDb ($i);
1334
                self::clearDb ();
1335 75
            }
1336 7
        } else {
1337 7
            self::getDb ();
1338 7
        }
1339
        return true;
1340 75
    }
1341 73
1342 73
    public static function clearDb () {
1343
        self::$db = NULL;
1344 75
    }
1345 75
1346
    public static function executeQuerySingle ($query, $database = NULL) {
1347 28
        return self::getDb ($database)->query($query)->fetchColumn();
1348 28
    }
1349 28
1350
    public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL, $sql = NULL) {
1351
        if (!$numberOfString) {
1352 28
            $numberOfString = $table . ".alphabetical";
1353 28
        }
1354 28
        if (is_null($sql)) {
1355
            $count = self::executeQuerySingle ('select count(*) from ' . $table);
1356 75
        } else {
1357 75
            $count = self::executeQuerySingle ($sql);
1358 75
        }
1359
        if ($count == 0) return NULL;
1360
        $entry = new Entry (localize($table . ".title"), $id,
1361
            str_format (localize($numberOfString, $count), $count), "text",
1362
            array ( new LinkNavigation ("?page=".$pageId)), "", $count);
1363
        return $entry;
1364
    }
1365
1366
    public static function getEntryArrayWithBookNumber ($query, $columns, $params, $category) {
1367
        /* @var $result PDOStatement */
1368
1369
        list (, $result) = self::executeQuery ($query, $columns, "", $params, -1);
1370
        $entryArray = array();
1371
        while ($post = $result->fetchObject ())
1372
        {
1373
            /* @var $instance Author|Tag|Serie|Publisher */
1374
1375
            $instance = new $category ($post);
1376
            if (property_exists($post, "sort")) {
1377
                $title = $post->sort;
1378
            } else {
1379
                $title = $post->name;
1380
            }
1381
            array_push ($entryArray, new Entry ($title, $instance->getEntryId (),
1382
                str_format (localize("bookword", $post->count), $post->count), "text",
1383
                array ( new LinkNavigation ($instance->getUri ())), "", $post->count));
1384
        }
1385
        return $entryArray;
1386
    }
1387
1388
    public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL, $max = NULL) {
1389
        $totalResult = -1;
1390
1391
        if (useNormAndUp ()) {
1392
            $query = preg_replace("/upper/", "normAndUp", $query);
1393
            $columns = preg_replace("/upper/", "normAndUp", $columns);
1394
        }
1395
1396
        if (is_null ($numberPerPage)) {
1397
            $numberPerPage = getCurrentOption ("max_item_per_page");
1398
        }
1399
1400
        if ($numberPerPage != -1 && $n != -1)
1401
        {
1402
            // First check total number of results
1403
            $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
1404
            $result->execute ($params);
1405
            $totalResult = $result->fetchColumn ();
1406
            $count = $numberPerPage;
1407
            if (!is_null($max) && $totalResult > $max) {
1408
                $totalResult = $max;
1409
                $left = $max - (($n - 1) * $numberPerPage);
1410
                if ($left < $count) {
1411
                    $count = $left;
1412
                }
1413
            }
1414
            
1415
            // Next modify the query and params
1416
            $query .= " limit ?, ?";
1417
            array_push ($params, ($n - 1) * $numberPerPage, $count);
1418
        }
1419
        
1420
        $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
1421
        $result->execute ($params);
1422
        return array ($totalResult, $result);
1423
    }
1424
1425
}
1426