Completed
Pull Request — master (#233)
by
unknown
11:31
created

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/**
3
 * COPS (Calibre OPDS PHP Server) class file
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     S�bastien Lucas <[email protected]>
7
 */
8
9
define ("VERSION", "1.0.0RC4");
10
define ("DB", "db");     // url parameter for the selected database
11
define ("VL", "vl");     // url parameter for the selected virtual library
12
date_default_timezone_set($config['default_timezone']);
13
14
require_once('virtuallib.php');
15
16
17
function useServerSideRendering () {
18 3
    global $config;
19 3
    return preg_match("/" . $config['cops_server_side_render'] . "/", $_SERVER['HTTP_USER_AGENT']);
20
}
21
22
function serverSideRender ($data) {
23
    // Get the templates
24 2
    $theme = getCurrentTemplate ();
25 2
    $header = file_get_contents('templates/' . $theme . '/header.html');
26 2
    $footer = file_get_contents('templates/' . $theme . '/footer.html');
27 2
    $main = file_get_contents('templates/' . $theme . '/main.html');
28 2
    $bookdetail = file_get_contents('templates/' . $theme . '/bookdetail.html');
29 2
    $page = file_get_contents('templates/' . $theme . '/page.html');
30
31
    // Generate the function for the template
32 2
    $template = new doT ();
33 2
    $dot = $template->template ($page, array ("bookdetail" => $bookdetail,
34 2
                                              "header" => $header,
35 2
                                              "footer" => $footer,
36 2
                                              "main" => $main));
37
    // If there is a syntax error in the function created
38
    // $dot will be equal to FALSE
39 2
    if (!$dot) {
40
        return FALSE;
41
    }
42
    // Execute the template
43 2
    if (!empty ($data)) {
44
        return $dot ($data);
45
    }
46
47 2
    return NULL;
48
}
49
50
function getQueryString () {
51 18
    if ( isset($_SERVER['QUERY_STRING']) ) {
52 16
        return $_SERVER['QUERY_STRING'];
53
    }
54 2
    return "";
55
}
56
57
function notFound () {
58
    header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
59
    header("Status: 404 Not Found");
60
61
    $_SERVER['REDIRECT_STATUS'] = 404;
62
}
63
64
function getURLParam ($name, $default = NULL) {
65 101
    if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != "") {
66 24
        return $_GET[$name];
67
    }
68 101
    return $default;
69
}
70
71
function getCurrentOption ($option) {
72 87
    global $config;
73 87
    if (isset($_COOKIE[$option])) {
74 2
        if (isset($config ["cops_" . $option]) && is_array ($config ["cops_" . $option])) {
75
            return explode (",", $_COOKIE[$option]);
76
        } else {
77 2
            return $_COOKIE[$option];
78
        }
79
    }
80 85
    if ($option == "style") {
81 2
        return "default";
82
    }
83
84 85
    if (isset($config ["cops_" . $option])) {
85 85
        return $config ["cops_" . $option];
86
    }
87
88
    return "";
89
}
90
91
function getCurrentCss () {
92 2
    return "templates/" . getCurrentTemplate () . "/styles/style-" . getCurrentOption ("style") . ".css";
93
}
94
95
function getCurrentTemplate () {
96 4
    return getCurrentOption ("template");
97
}
98
99
function getUrlWithVersion ($url) {
100 50
    return $url . "?v=" . VERSION;
101
}
102
103
function xml2xhtml($xml) {
104 35
    return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', create_function('$m', '
105
        $xhtml_tags = array("br", "hr", "input", "frame", "img", "area", "link", "col", "base", "basefont", "param");
106
        return in_array($m[1], $xhtml_tags) ? "<$m[1]$m[2] />" : "<$m[1]$m[2]></$m[1]>";
107 35
    '), $xml);
108
}
109
110
function display_xml_error($error)
111
{
112
    $return = "";
113
    $return .= str_repeat('-', $error->column) . "^\n";
114
115
    switch ($error->level) {
116
        case LIBXML_ERR_WARNING:
117
            $return .= "Warning $error->code: ";
118
            break;
119
         case LIBXML_ERR_ERROR:
120
            $return .= "Error $error->code: ";
121
            break;
122
        case LIBXML_ERR_FATAL:
123
            $return .= "Fatal Error $error->code: ";
124
            break;
125
    }
126
127
    $return .= trim($error->message) .
128
               "\n  Line: $error->line" .
129
               "\n  Column: $error->column";
130
131
    if ($error->file) {
132
        $return .= "\n  File: $error->file";
133
    }
134
135
    return "$return\n\n--------------------------------------------\n\n";
136
}
137
138
function are_libxml_errors_ok ()
139
{
140 35
    $errors = libxml_get_errors();
141
142 35
    foreach ($errors as $error) {
143
        if ($error->code == 801) return false;
144 35
    }
145 35
    return true;
146
}
147
148
function html2xhtml ($html) {
149 35
    $doc = new DOMDocument();
150 35
    libxml_use_internal_errors(true);
151
152 35
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
153 35
                        $html  . '</body></html>'); // Load the HTML
154 35
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
155 35
    $output = xml2xhtml($output);
156 35
    if (preg_match ('#<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></meta></head><body>(.*)</body></html>#ms', $output, $matches)) {
157 35
        $output = $matches [1]; // Remove <html><body>
158 35
    }
159
    /*
160
    // In case of error with summary, use it to debug
161
    $errors = libxml_get_errors();
162
163
    foreach ($errors as $error) {
164
        $output .= display_xml_error($error);
165
    }
166
    */
167
168 35
    if (!are_libxml_errors_ok ()) $output = "HTML code not valid.";
169
170 35
    libxml_use_internal_errors(false);
171 35
    return $output;
172
}
173
174
/**
175
 * This method is a direct copy-paste from
176
 * http://tmont.com/blargh/2010/1/string-format-in-php
177
 */
178
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...
179 94
    $args = func_get_args();
180 94
    $format = array_shift($args);
181
182 94
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
183 94
    $offset = 0;
184 94
    foreach ($matches[1] as $data) {
185 94
        $i = $data[0];
186 94
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
187 94
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
188 94
    }
189
190 94
    return $format;
191
}
192
193
/**
194
 * Format strings using named parameters.
195
 *
196
 * This method replaces {name} in the format string with the value of $array["name"].
197
 * @param string $format a format string with named parameters.
198
 * @param array $array an array with named values to use as parameters.
199 16
 */
200
function str_format_n($format, $array) {
201 16
202
	preg_match_all('/(?=\{)\{([\w\d]+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
203 16
	$offset = 0;
204 16
	foreach ($matches[1] as $data) {
205
		$name = $data[0];
206 3
		if (array_key_exists($name, $array)) {
207 3
			$format = substr_replace($format, $array[$name], $offset + $data[1] - 1, 2 + strlen($name));
208 16
			$offset += strlen($array[$name]) - 2 - strlen($name);
209
		} else {
210 16
			// Replace not existent keys by ""
211 16
			$format = substr_replace($format, "", $offset + $data[1] - 1, 2 + strlen($name));
212 16
			$offset += 0 - 2 - strlen($name);
213
		}
214 16
	}
215 11
216 11
	return $format;
217 11
}
218 11
219 16
/**
220 16
 * Get all accepted languages from the browser and put them in a sorted array
221
 * languages id are normalized : fr-fr -> fr_FR
222 16
 * @return array of languages
223
 */
224
function getAcceptLanguages() {
225 16
    $langs = array();
226 16
227 16
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
228
        // break up string into pieces (languages and q factors)
229
        $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
230 16
        if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) {
231 16
            // Special fix for IE11 which send fr-FR and nothing else
232 16
            $accept = $accept . "," . $matches[1] . ";q=0.8";
233
        }
234 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);
235
236
        if (count($lang_parse[1])) {
237
            $langs = array();
238
            foreach ($lang_parse[1] as $lang) {
239
                // Format the language code (not standard among browsers)
240
                if (strlen($lang) == 5) {
241
                    $lang = str_replace("-", "_", $lang);
242 17
                    $splitted = preg_split("/_/", $lang);
243 17
                    $lang = $splitted[0] . "_" . strtoupper($splitted[1]);
244 17
                }
245 17
                array_push($langs, $lang);
246
            }
247
            // create a list like "en" => 0.8
248 17
            $langs = array_combine($langs, $lang_parse[4]);
249 16
250 16
            // set default to 1 for any without q factor
251
            foreach ($langs as $lang => $val) {
252 17
                if ($val === '') $langs[$lang] = 1;
253 17
            }
254 16
255 16
            // sort list based on value
256 16
            arsort($langs, SORT_NUMERIC);
257 16
        }
258 16
    }
259
260 17
    return $langs;
261 17
}
262 3
263 3
/**
264 17
 * Find the best translation file possible based on the accepted languages
265
 * @return array of language and language file
266
 */
267
function getLangAndTranslationFile() {
268
    global $config;
269
    $langs = array();
270
    $lang = "en";
271
    if (!empty($config['cops_language'])) {
272 114
        $lang = $config['cops_language'];
273 114
    }
274 114
    elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
275 114
        $langs = getAcceptLanguages();
276 114
    }
277 114
    //echo var_dump($langs);
278 114
    $lang_file = NULL;
279
    foreach ($langs as $language => $val) {
280
        $temp_file = dirname(__FILE__). '/lang/Localization_' . $language . '.json';
281 114
        if (file_exists($temp_file)) {
282 114
            $lang = $language;
283 16
            $lang_file = $temp_file;
284 16
            break;
285
        }
286 114
    }
287 17
    if (empty ($lang_file)) {
288 17
        $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
289 17
    }
290 1
    return array($lang, $lang_file);
291 1
}
292
293 17
/**
294
 * This method is based on this page
295 17
 * http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/
296
 */
297
function localize($phrase, $count=-1, $reset=false) {
298 17
    global $config;
299 17
    if ($count == 0)
300 1
        $phrase .= ".none";
301 1
    if ($count == 1)
302 17
        $phrase .= ".one";
303
    if ($count > 1)
304 17
        $phrase .= ".many";
305 1
306 1
    /* Static keyword is used to ensure the file is loaded only once */
307 1
    static $translations = NULL;
308 1
    if ($reset) {
309 17
        $translations = NULL;
310 114
    }
311 114
    /* If no instance of $translations has occured load the language file */
312
    if (is_null($translations)) {
313 1
        $lang_file_en = NULL;
314
        list ($lang, $lang_file) = getLangAndTranslationFile();
315
        if ($lang != "en") {
316
            $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
317 58
        }
318 48
319 48
        $lang_file_content = file_get_contents($lang_file);
320 58
        /* Load the language file as a JSON object and transform it into an associative array */
321 58
        $translations = json_decode($lang_file_content, true);
322 15
323 15
        /* Clean the array of all unfinished translations */
324 15
        foreach (array_keys ($translations) as $key) {
325 58
            if (preg_match ("/^##TODO##/", $key)) {
326 58
                unset ($translations [$key]);
327 58
            }
328
        }
329
        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...
330 58
        {
331
            $lang_file_content = file_get_contents($lang_file_en);
332 58
            $translations_en = json_decode($lang_file_content, true);
333
            $translations = array_merge ($translations_en, $translations);
334
        }
335
    }
336 107
    if (array_key_exists ($phrase, $translations)) {
337 107
        return $translations[$phrase];
338
    }
339
    return $phrase;
340
}
341 8
342 8
function addURLParameter($urlParams, $paramName, $paramValue) {
343
    if (empty ($urlParams)) {
344
        $urlParams = "";
345
    }
346 7
    $start = "";
347
    if (preg_match ("#^\?(.*)#", $urlParams, $matches)) {
348
        $start = "?";
349
        $urlParams = $matches[1];
350
    }
351
    $params = array();
352
    parse_str($urlParams, $params);
353
    if (empty ($paramValue) && $paramValue != 0) {
354
        unset ($params[$paramName]);
355
    } else {
356
        $params[$paramName] = $paramValue;
357
    }
358
    return $start . http_build_query($params);
359
}
360
361
function useNormAndUp () {
362
    global $config;
363
    return $config ['cops_normalized_search'] == "1";
364 96
}
365 96
366 96
function normalizeUtf8String( $s) {
367 96
    include_once 'transliteration.php';
368 96
    return _transliteration_process($s);
369 96
}
370 96
371 96
function normAndUp ($s) {
372
    return mb_strtoupper (normalizeUtf8String($s), 'UTF-8');
373 10
}
374 10
375
class Link
376
{
377
    const OPDS_THUMBNAIL_TYPE = "http://opds-spec.org/image/thumbnail";
378
    const OPDS_IMAGE_TYPE = "http://opds-spec.org/image";
379
    const OPDS_ACQUISITION_TYPE = "http://opds-spec.org/acquisition";
380 95
    const OPDS_NAVIGATION_TYPE = "application/atom+xml;profile=opds-catalog;kind=navigation";
381 95
    const OPDS_PAGING_TYPE = "application/atom+xml;profile=opds-catalog;kind=acquisition";
382 95
383 1
    public $href;
384 1
    public $type;
385 1
    public $rel;
386 95
    public $title;
387 95
    public $facetGroup;
388
    public $activeFacet;
389
390 95
    public function __construct($phref, $ptype, $prel = NULL, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
391
        $this->href = $phref;
392 95
        $this->type = $ptype;
393
        $this->rel = $prel;
394
        $this->title = $ptitle;
395
        $this->facetGroup = $pfacetGroup;
396
        $this->activeFacet = $pactiveFacet;
397 1
    }
398 1
399 1
    public function hrefXhtml () {
400
        return $this->href;
401
    }
402
}
403 1
404 1
class LinkNavigation extends Link
405
{
406
    public function __construct($phref, $prel = NULL, $ptitle = NULL) {
407
        parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
408
        if (!is_null (GetUrlParam (DB))) {
409
        	$this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
410
        	$this->href = addURLParameter ($this->href, VL, GetUrlParam (VL, 0));
411
        }
412
        if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
413
        if (preg_match ("/(bookdetail|getJSON).php/", $_SERVER["SCRIPT_NAME"])) {
414
            $this->href = "index.php" . $this->href;
415
        } else {
416
            $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
417
        }
418
    }
419
}
420
421
class LinkFacet extends Link
422
{
423
    public function __construct($phref, $ptitle = NULL, $pfacetGroup = NULL, $pactiveFacet = FALSE) {
424
        parent::__construct ($phref, Link::OPDS_PAGING_TYPE, "http://opds-spec.org/facet", $ptitle, $pfacetGroup, $pactiveFacet);
425
        if (!is_null (GetUrlParam (DB))) {
426
        	$this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
427
        	$this->href = addURLParameter ($this->href, VL, GetUrlParam (VL, 0));
428
        }
429
        $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
430
    }
431
}
432
433
class Entry
434
{
435
    public $title;
436
    public $id;
437
    public $content;
438
    public $numberOfElement;
439
    public $contentType;
440
    public $linkArray;
441 7
    public $localUpdated;
442 7
    public $className;
443 7
    private static $updated = NULL;
444
445 7
    public static $icons = array(
446
        Author::ALL_AUTHORS_ID       => 'images/author.png',
447
        Serie::ALL_SERIES_ID         => 'images/serie.png',
448
        Book::ALL_RECENT_BOOKS_ID    => 'images/recent.png',
449
        Tag::ALL_TAGS_ID             => 'images/tag.png',
450 89
        Language::ALL_LANGUAGES_ID   => 'images/language.png',
451 89
        CustomColumn::ALL_CUSTOMS_ID => 'images/tag.png',
452 89
        "cops:books$"             => 'images/allbook.png',
453 89
        "cops:books:letter"       => 'images/allbook.png',
454 89
        Publisher::ALL_PUBLISHERS_ID => 'images/publisher.png'
455 89
    );
456 89
457 89
    public function getUpdatedTime () {
458 89
        if (!is_null ($this->localUpdated)) {
459
            return date (DATE_ATOM, $this->localUpdated);
460 89
        }
461 89
        if (is_null (self::$updated)) {
462 89
            self::$updated = time();
463
        }
464 89
        return date (DATE_ATOM, self::$updated);
465 50
    }
466 50
467
    public function getNavLink () {
468 89
        foreach ($this->linkArray as $link) {
469 89
            if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
470
471 89
            return $link->hrefXhtml ();
472 89
        }
473
        return "#";
474
    }
475
476
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pclass = "", $pcount = 0) {
477
        global $config;
478
        $this->title = $ptitle;
479 39
        $this->id = $pid;
480 39
        $this->content = $pcontent;
481 39
        $this->contentType = $pcontentType;
482 39
        $this->linkArray = $plinkArray;
483 39
        $this->className = $pclass;
484
        $this->numberOfElement = $pcount;
485
486
        if ($config['cops_show_icons'] == 1)
487
        {
488
            foreach (self::$icons as $reg => $image)
489
            {
490
                if (preg_match ("/" . $reg . "/", $pid)) {
491
                    array_push ($this->linkArray, new Link (getUrlWithVersion ($image), "image/png", Link::OPDS_THUMBNAIL_TYPE));
492
                    break;
493
                }
494
            }
495
        }
496
497
        if (!is_null (GetUrlParam (DB))) $this->id = str_replace ("cops:", "cops:" . GetUrlParam (DB) . ":" . GetUrlParam (VL,0) . ":", $this->id);
498
    }
499
}
500
501
class EntryBook extends Entry
502
{
503
    public $book;
504
505
    public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray, $pbook) {
506
        parent::__construct ($ptitle, $pid, $pcontent, $pcontentType, $plinkArray);
507
        $this->book = $pbook;
508
        $this->localUpdated = $pbook->timestamp;
509
    }
510
511
    public function getCoverThumbnail () {
512
        foreach ($this->linkArray as $link) {
513
            if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
514
                return $link->hrefXhtml ();
515
        }
516
        return null;
517
    }
518 81
519
    public function getCover () {
520
        foreach ($this->linkArray as $link) {
521 81
            if ($link->rel == Link::OPDS_IMAGE_TYPE)
522 3
                return $link->hrefXhtml ();
523 78
        }
524 1
        return null;
525 77
    }
526 7
}
527 70
528 2
class Page
529 68
{
530 1
    public $title;
531 67
    public $subtitle = "";
532 2
    public $authorName = "";
533 65
    public $authorUri = "";
534 1
    public $authorEmail = "";
535 64
    public $idPage;
536 3
    public $idGet;
537 61
    public $query;
538 3
    public $favicon;
539 58
    public $n;
540 1
    public $book;
541 57
    public $totalNumber = -1;
542 1
    public $entryArray = array();
543 56
544 2
    public static function getPage ($pageId, $id, $query, $n)
545 54
    {
546 3
        switch ($pageId) {
547 51
            case Base::PAGE_ALL_AUTHORS :
548 1
                return new PageAllAuthors ($id, $query, $n);
549 50
            case Base::PAGE_AUTHORS_FIRST_LETTER :
550 4
                return new PageAllAuthorsLetter ($id, $query, $n);
551 46
            case Base::PAGE_AUTHOR_DETAIL :
552 1
                return new PageAuthorDetail ($id, $query, $n);
553 45
            case Base::PAGE_ALL_TAGS :
554 31
                return new PageAllTags ($id, $query, $n);
555 14
            case Base::PAGE_TAG_DETAIL :
556 1
                return new PageTagDetail ($id, $query, $n);
557 13
            case Base::PAGE_ALL_LANGUAGES :
558 2
                return new PageAllLanguages ($id, $query, $n);
559 11
            case Base::PAGE_LANGUAGE_DETAIL :
560 1
                return new PageLanguageDetail ($id, $query, $n);
561 10
            case Base::PAGE_ALL_CUSTOMS :
562
                return new PageAllCustoms ($id, $query, $n);
563 10
            case Base::PAGE_CUSTOM_DETAIL :
564
                return new PageCustomDetail ($id, $query, $n);
565 10
            case Base::PAGE_ALL_RATINGS :
566 10
                return new PageAllRating ($id, $query, $n);
567 10
            case Base::PAGE_RATING_DETAIL :
568 10
                return new PageRatingDetail ($id, $query, $n);
569 10
            case Base::PAGE_ALL_SERIES :
570
                return new PageAllSeries ($id, $query, $n);
571
            case Base::PAGE_ALL_BOOKS :
572 81
                return new PageAllBooks ($id, $query, $n);
573 81
            case Base::PAGE_ALL_BOOKS_LETTER:
574
                return new PageAllBooksLetter ($id, $query, $n);
575 81
            case Base::PAGE_ALL_RECENT_BOOKS :
576 81
                return new PageRecentBooks ($id, $query, $n);
577 81
            case Base::PAGE_SERIE_DETAIL :
578 81
                return new PageSerieDetail ($id, $query, $n);
579 81
            case Base::PAGE_OPENSEARCH_QUERY :
580 81
                return new PageQueryResult ($id, $query, $n);
581 81
            case Base::PAGE_BOOK_DETAIL :
582 81
                return new PageBookDetail ($id, $query, $n);
583
            case Base::PAGE_ALL_PUBLISHERS:
584 10
                return new PageAllPublishers ($id, $query, $n);
585
            case Base::PAGE_PUBLISHER_DETAIL :
586 10
                return new PagePublisherDetail ($id, $query, $n);
587 10
            case Base::PAGE_ABOUT :
588 10
                return new PageAbout ($id, $query, $n);
589 10
            case Base::PAGE_CUSTOMIZE :
590 2
                return new PageCustomize ($id, $query, $n);
591 2
            default:
592 2
                $page = new Page ($id, $query, $n);
593
                $page->idPage = "cops:catalog";
594
                return $page;
595
        }
596
    }
597
598
    public function __construct($pid, $pquery, $pn) {
599
        global $config;
600
601
        $this->idGet = $pid;
602
        $this->query = $pquery;
603
        $this->n = $pn;
604
        $this->favicon = $config['cops_icon'];
605 2
        $this->authorName = empty($config['cops_author_name']) ? utf8_encode('S�bastien Lucas') : $config['cops_author_name'];
606 2
        $this->authorUri = empty($config['cops_author_uri']) ? 'http://blog.slucas.fr' : $config['cops_author_uri'];
607 2
        $this->authorEmail = empty($config['cops_author_email']) ? '[email protected]' : $config['cops_author_email'];
608 2
    }
609
610 2
    public function InitializeContent ()
611 2
    {
612 2
        global $config;
613 2
        $this->title = $config['cops_title_default'];
614 8
        $this->subtitle = $config['cops_subtitle_default'];
615 7
        if (Base::noDatabaseSelected ()) {
616 7
            $i = 0;
617 8
            foreach (Base::getDbNameList () as $key) {
618 7
            	$j = 0;
619 7
            	// if virtual libraries are nor enabled, getVLNameList() contains just one empty entry
620 7
            	foreach (VirtualLib::getVLNameList($i) as $vlName) {
621 8
            		$nBooks = Book::getBookCount ($i, $j);
622 7
            		array_push ($this->entryArray, new Entry (VirtualLib::getDisplayName($key, $vlName),
623 7
            							"cops:{$i}:{$j}:catalog",
624 7
            							str_format (localize ("bookword", $nBooks), $nBooks), "text",
625 8
            							array ( new LinkNavigation ("?" . DB . "={$i}&" . VL . "={$j}")), "", $nBooks));
626 7
            		$j++;
627 7
            	}
628 7
                $i++;
629 8
                Base::clearDb ();
630 8
            }
631 8
        } else {
632 8
            if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) {
633 8
                array_push ($this->entryArray, Author::getCount());
634 7
            }
635 7
            if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) {
636 7
                $series = Serie::getCount();
637 8
                if (!is_null ($series)) array_push ($this->entryArray, $series);
638 4
            }
639 4
            if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) {
640 4
                $publisher = Publisher::getCount();
641 4
                if (!is_null ($publisher)) array_push ($this->entryArray, $publisher);
642 8
            }
643 8
            if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) {
644
                $tags = Tag::getCount();
645 8
                if (!is_null ($tags)) array_push ($this->entryArray, $tags);
646
            }
647 10
            if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) {
648
                $rating = Rating::getCount();
649 17
                if (!is_null ($rating)) array_push ($this->entryArray, $rating);
650
            }
651 17
            if (!in_array ("language", getCurrentOption ('ignored_categories'))) {
652 17
                $languages = Language::getCount();
653 17
                if (!is_null ($languages)) array_push ($this->entryArray, $languages);
654
            }
655
            foreach ($config['cops_calibre_custom_column'] as $lookup) {
656 2
                $customId = CustomColumn::getCustomId ($lookup);
657
                if (!is_null ($customId)) {
658 2
                    array_push ($this->entryArray, CustomColumn::getCount($customId));
659 2
                }
660 1
            }
661
            $this->entryArray = array_merge ($this->entryArray, Book::getCount());
662 1
663
            if (Base::isDatabaseArray ()) $this->title =  VirtualLib::getDisplayName();
664
        }
665 2
    }
666
667 2
    public function isPaginated ()
668 2
    {
669 1
        return (getCurrentOption ("max_item_per_page") != -1 &&
670
                $this->totalNumber != -1 &&
671 2
                $this->totalNumber > getCurrentOption ("max_item_per_page"));
672
    }
673
674 2
    public function getNextLink ()
675
    {
676 2
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
677
        if (($this->n) * getCurrentOption ("max_item_per_page") < $this->totalNumber) {
678
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n + 1), "next", localize ("paging.next.alternate"));
679 70
        }
680
        return NULL;
681 70
    }
682 68
683 46
    public function getPrevLink ()
684
    {
685
        $currentUrl = preg_replace ("/\&n=.*?$/", "", "?" . getQueryString ());
686
        if ($this->n > 1) {
687
            return new LinkNavigation ($currentUrl . "&n=" . ($this->n - 1), "previous", localize ("paging.previous.alternate"));
688
        }
689 3
        return NULL;
690
    }
691 3
692 3
    public function getMaxPage ()
693 2
    {
694 2
        return ceil ($this->totalNumber / getCurrentOption ("max_item_per_page"));
695
    }
696 1
697
    public function containsBook ()
698 3
    {
699 3
        if (count ($this->entryArray) == 0) return false;
700
        if (get_class ($this->entryArray [0]) == "EntryBook") return true;
701
        return false;
702
    }
703
}
704 1
705
class PageAllAuthors extends Page
706 1
{
707 1
    public function InitializeContent ()
708 1
    {
709 1
        $this->title = localize("authors.title");
710
        if (getCurrentOption ("author_split_first_letter") == 1) {
711
            $this->entryArray = Author::getAllAuthorsByFirstLetter();
712
        }
713
        else {
714 7
            $this->entryArray = Author::getAllAuthors();
715
        }
716 7
        $this->idPage = Author::ALL_AUTHORS_ID;
717 7
    }
718 7
}
719 7
720 7
class PageAllAuthorsLetter extends Page
721
{
722
    public function InitializeContent ()
723
    {
724
        $this->idPage = Author::getEntryIdByLetter ($this->idGet);
725 2
        $this->entryArray = Author::getAuthorsByStartingLetter ($this->idGet);
726
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("authorword", count ($this->entryArray)), count ($this->entryArray)), $this->idGet);
727 2
    }
728 2
}
729 2
730 2
class PageAuthorDetail extends Page
731
{
732
    public function InitializeContent ()
733
    {
734
        $author = Author::getAuthorById ($this->idGet);
735 1
        $this->idPage = $author->getEntryId ();
736
        $this->title = $author->name;
737 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByAuthor ($this->idGet, $this->n);
738 1
    }
739 1
}
740 1
741 1
class PageAllPublishers extends Page
742
{
743
    public function InitializeContent ()
744
    {
745
        $this->title = localize("publishers.title");
746 2
        $this->entryArray = Publisher::getAllPublishers();
747
        $this->idPage = Publisher::ALL_PUBLISHERS_ID;
748 2
    }
749 2
}
750 2
751 2
class PagePublisherDetail extends Page
752
{
753
    public function InitializeContent ()
754
    {
755
        $publisher = Publisher::getPublisherById ($this->idGet);
756 2
        $this->title = $publisher->name;
757
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByPublisher ($this->idGet, $this->n);
758 2
        $this->idPage = $publisher->getEntryId ();
759 2
    }
760 2
}
761 2
762
class PageAllTags extends Page
763
{
764
    public function InitializeContent ()
765
    {
766 3
        $this->title = localize("tags.title");
767
        $this->entryArray = Tag::getAllTags();
768 3
        $this->idPage = Tag::ALL_TAGS_ID;
769 3
    }
770 3
}
771 3
772 3
class PageAllLanguages extends Page
773 3
{
774
    public function InitializeContent ()
775
    {
776
        $this->title = localize("languages.title");
777
        $this->entryArray = Language::getAllLanguages();
778 3
        $this->idPage = Language::ALL_LANGUAGES_ID;
779
    }
780 3
}
781 3
782 3
class PageCustomDetail extends Page
783 3
{
784 3
    public function InitializeContent ()
785
    {
786
        $customId = getURLParam ("custom", NULL);
787
        $custom = CustomColumn::getCustomById ($customId, $this->idGet);
788
        $this->idPage = $custom->getEntryId ();
789 1
        $this->title = $custom->name;
790
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByCustom ($customId, $this->idGet, $this->n);
791 1
    }
792 1
}
793 1
794 1
class PageAllCustoms extends Page
795 1
{
796
    public function InitializeContent ()
797
    {
798
        $customId = getURLParam ("custom", NULL);
799
        $this->title = CustomColumn::getAllTitle ($customId);
800 1
        $this->entryArray = CustomColumn::getAllCustoms($customId);
801
        $this->idPage = CustomColumn::getAllCustomsId ($customId);
802 1
    }
803 1
}
804 1
805 1
class PageTagDetail extends Page
806 1
{
807
    public function InitializeContent ()
808
    {
809
        $tag = Tag::getTagById ($this->idGet);
810
        $this->idPage = $tag->getEntryId ();
811 2
        $this->title = $tag->name;
812
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByTag ($this->idGet, $this->n);
813 2
    }
814 2
}
815 2
816 2
class PageLanguageDetail extends Page
817
{
818
    public function InitializeContent ()
819
    {
820
        $language = Language::getLanguageById ($this->idGet);
821 1
        $this->idPage = $language->getEntryId ();
822
        $this->title = $language->lang_code;
823 1
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByLanguage ($this->idGet, $this->n);
824 1
    }
825 1
}
826 1
827 1
class PageAllSeries extends Page
828
{
829
    public function InitializeContent ()
830
    {
831
        $this->title = localize("series.title");
832 1
        $this->entryArray = Serie::getAllSeries();
833
        $this->idPage = Serie::ALL_SERIES_ID;
834 1
    }
835 1
}
836 1
837 1
class PageSerieDetail extends Page
838
{
839
    public function InitializeContent ()
840
    {
841
        $serie = Serie::getSerieById ($this->idGet);
842 1
        $this->title = $serie->name;
843
        list ($this->entryArray, $this->totalNumber) = Book::getBooksBySeries ($this->idGet, $this->n);
844 1
        $this->idPage = $serie->getEntryId ();
845 1
    }
846 1
}
847 1
848 1
class PageAllRating extends Page
849
{
850
    public function InitializeContent ()
851
    {
852
        $this->title = localize("ratings.title");
853 3
        $this->entryArray = Rating::getAllRatings();
854
        $this->idPage = Rating::ALL_RATING_ID;
855 3
    }
856 3
}
857 2
858 2
class PageRatingDetail extends Page
859
{
860 1
    public function InitializeContent ()
861
    {
862 3
        $rating = Rating::getRatingById ($this->idGet);
863 3
        $this->idPage = $rating->getEntryId ();
864
        $this->title =str_format (localize ("ratingword", $rating->name/2), $rating->name/2);
865
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByRating ($this->idGet, $this->n);
866
    }
867
}
868 1
869
class PageAllBooks extends Page
870 1
{
871 1
    public function InitializeContent ()
872
    {
873 1
        $this->title = localize ("allbooks.title");
874 1
        if (getCurrentOption ("titles_split_first_letter") == 1) {
875 1
            $this->entryArray = Book::getAllBooks();
876
        }
877 1
        else {
878 1
            list ($this->entryArray, $this->totalNumber) = Book::getBooks ($this->n);
879
        }
880
        $this->idPage = Book::ALL_BOOKS_ID;
881
    }
882
}
883 4
884
class PageAllBooksLetter extends Page
885 4
{
886 4
    public function InitializeContent ()
887 4
    {
888 4
        list ($this->entryArray, $this->totalNumber) = Book::getBooksByStartingLetter ($this->idGet, $this->n);
889
        $this->idPage = Book::getEntryIdByLetter ($this->idGet);
890
891
        $count = $this->totalNumber;
892
        if ($count == -1)
893
            $count = count ($this->entryArray);
894
895
        $this->title = str_format (localize ("splitByLetter.letter"), str_format (localize ("bookword", $count), $count), $this->idGet);
896
    }
897
}
898
899
class PageRecentBooks extends Page
900 24
{
901 24
    public function InitializeContent ()
902
    {
903
        $this->title = localize ("recent.title");
904 29
        $this->entryArray = Book::getAllRecentBooks ();
905 29
        $this->idPage = Book::ALL_RECENT_BOOKS_ID;
906 29
    }
907 29
}
908 29
909 7
class PageQueryResult extends Page
910 7
{
911 29
    const SCOPE_TAG = "tag";
912 22
    const SCOPE_RATING = "rating";
913 22
    const SCOPE_SERIES = "series";
914 22
    const SCOPE_AUTHOR = "author";
915
    const SCOPE_BOOK = "book";
916 29
    const SCOPE_PUBLISHER = "publisher";
917 23
918 23
    private function useTypeahead () {
919 28
        return !is_null (getURLParam ("search"));
920 23
    }
921 23
922 25
    private function searchByScope ($scope, $limit = FALSE) {
923 22
        $n = $this->n;
924 22
        $numberPerPage = NULL;
925 24
        $queryNormedAndUp = $this->query;
926 23
        if (useNormAndUp ()) {
927 23
            $queryNormedAndUp = normAndUp ($this->query);
928 23
        }
929 23
        if ($limit) {
930 23
            $n = 1;
931
            $numberPerPage = 5;
932
        }
933
        switch ($scope) {
934
            case self::SCOPE_BOOK :
935
                $array = Book::getBooksByStartingLetter ('%' . $queryNormedAndUp, $n, NULL, NULL, $numberPerPage);
936 29
                break;
937
            case self::SCOPE_AUTHOR :
938
                $array = Author::getAuthorsForSearch ('%' . $queryNormedAndUp);
939 22
                break;
940 22
            case self::SCOPE_SERIES :
941 22
                $array = Serie::getAllSeriesByQuery ($queryNormedAndUp);
942 22
                break;
943 22
            case self::SCOPE_TAG :
944 22
                $array = Tag::getAllTagsByQuery ($queryNormedAndUp, $n, NULL, $numberPerPage);
945 22
                break;
946 22
            case self::SCOPE_PUBLISHER :
947
                $array = Publisher::getAllPublishersByQuery ($queryNormedAndUp);
948 22
                break;
949 1
            default:
950 1
                $array = Book::getBooksByQuery (
951 1
                    array ("all" => "%" . $queryNormedAndUp . "%"), $n);
952 22
        }
953 22
954 22
        return $array;
955
    }
956 22
957 22
    public function doSearchByCategory () {
958
        $database = GetUrlParam (DB);
959
        $virtualLib = getURLParam(VL, 0);
960
        $out = array ();
961
        $pagequery = Base::PAGE_OPENSEARCH_QUERY;
962
        $dbArray = array ("");
963 22
        $d = $database;
964 22
        $query = $this->query;
965 1
        // Special case when no databases were chosen, we search on all databases
966 1
        if (Base::noDatabaseSelected ()) {
967 1
            $dbArray = Base::getDbNameList ();
968 1
            $d = 0;
969 1
        }
970
        $vl = $virtualLib;
971 1
        $vlArray = VirtualLib::getVLNameList($d);
972 22
        $vlArray = array($vlArray[$vl]);
973 22
        
974 22
        foreach ($dbArray as $dbKey) {
975 22
        	if (Base::noDatabaseSelected () && VirtualLib::isVLEnabled()) {
976 22
        		// If virtual libraries are enabled, but no Database is selected, 
977 22
        		// then iterate over all virtual libraries
978 3
        		$vlArray = VirtualLib::getVLNameList($d);
979
        		$vl = 0;
980 22
        	}
981
        	foreach ($vlArray as $vlKey) {	
982 22
	            if (Base::noDatabaseSelected ()) {
983 22
	                array_push ($this->entryArray, new Entry (VirtualLib::getDisplayName($dbKey, $vlKey), 
984 22
	                						DB . ":query:{$d}:{$vl}",
985 22
	                                        " ", "text",
986 22
	                                        array ( new LinkNavigation ("?" . DB . "={$d}&" . VL . "={$vl}")), "tt-header"));
987 22
	                Base::getDb ($d);
988
	                // TODO: set current virtual library in Base Or VirtualLib
989 22
	            }
990
	            foreach (array (PageQueryResult::SCOPE_BOOK,
991
	                            PageQueryResult::SCOPE_AUTHOR,
992
	                            PageQueryResult::SCOPE_SERIES,
993
	                            PageQueryResult::SCOPE_TAG,
994
	                            PageQueryResult::SCOPE_PUBLISHER) as $key) {
995
	                if (in_array($key, getCurrentOption ('ignored_categories'))) {
996 21
	                    continue;
997 21
	                }
998 21
	                $array = $this->searchByScope ($key, TRUE);
999 21
	
1000 21
	                $i = 0;
1001 22
	                if (count ($array) == 2 && is_array ($array [0])) {
1002 6
	                    $total = $array [1];
1003 6
	                    $array = $array [0];
1004 6
	                } else {
1005 6
	                    $total = count($array);
1006 6
	                }
1007 6
	                if ($total > 0) {
1008 22
	                    // Comment to help the perl i18n script
1009 22
	                    // str_format (localize("bookword", count($array))
1010 22
	                    // str_format (localize("authorword", count($array))
1011 22
	                    // str_format (localize("seriesword", count($array))
1012 22
	                    // str_format (localize("tagword", count($array))
1013 1
	                    // str_format (localize("publisherword", count($array))
1014 1
	                    array_push ($this->entryArray, new Entry (str_format (localize ("search.result.{$key}"), $this->query), DB . ":query:{$d}:{$key}:{$vl}",
1015 22
	                                        str_format (localize("{$key}word", $total), $total), "text",
1016 22
	                                        array ( new LinkNavigation ("?page={$pagequery}&query={$query}&db={$d}&vl={$vl}&scope={$key}")),
1017
	                                        Base::noDatabaseSelected () ? "" : "tt-header", $total));
1018
	                }
1019 31
	                if (!Base::noDatabaseSelected () && $this->useTypeahead ()) {
1020
	                    foreach ($array as $entry) {
1021 31
	                        array_push ($this->entryArray, $entry);
1022 31
	                        $i++;
1023 24
	                        if ($i > 4) { break; };
1024 24
	                    }
1025
	                }
1026
	            }
1027
	            $vl++;
1028
        	}
1029
            $d++;
1030
            if (Base::noDatabaseSelected ()) {
1031 7
                Base::clearDb ();
1032
            }
1033
        }
1034 31
        return $out;
1035
    }
1036
1037 31
	public function InitializeContent ()
1038 2
    {
1039 2
        $scope = getURLParam ("scope");
1040 2
        if (empty ($scope)) {
1041 2
            $this->title = str_format (localize ("search.result"), $this->query);
1042 2
        } else {
1043 2
            // Comment to help the perl i18n script
1044 2
            // str_format (localize ("search.result.author"), $this->query)
1045 2
            // str_format (localize ("search.result.tag"), $this->query)
1046 2
            // str_format (localize ("search.result.series"), $this->query)
1047 2
            // str_format (localize ("search.result.book"), $this->query)
1048
            // str_format (localize ("search.result.publisher"), $this->query)
1049 29
            $this->title = str_format (localize ("search.result.{$scope}"), $this->query);
1050 22
        }
1051 22
1052
        $crit = "%" . $this->query . "%";
1053
1054 7
        // Special case when we are doing a search and no database is selected
1055 7
        if (Base::noDatabaseSelected () && !$this->useTypeahead ()) {
1056 2
            $i = 0;
1057 2
            foreach (Base::getDbNameList () as $dbKey) {
1058 5
                Base::clearDb ();
1059
                $j = 0;
1060 7
                foreach (VirtualLib::getVLNameList($i) as $vlKey) {
1061
	                list ($array, $totalNumber) = Book::getBooksByQuery (array ("all" => $crit), 1, $i, $j, 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...
1062
	                array_push ($this->entryArray, new Entry (VirtualLib::getDisplayName($dbKey, $vlKey), 
1063
	                						DB . ":query:{$i}:{$j}",
1064
	                                        str_format (localize ("bookword", $totalNumber), $totalNumber), "text",
1065 1
	                                        array ( new LinkNavigation ("?" . DB . "={$i}&page=9&query=" . $this->query)), "", $totalNumber));
1066
	                $j++;
1067 1
                }
1068 1
                $i++;
1069 1
            }
1070
            return;
1071
        }
1072
        if (empty ($scope)) {
1073
            $this->doSearchByCategory ();
1074
            return;
1075
        }
1076
1077
        $array = $this->searchByScope ($scope);
1078
        if (count ($array) == 2 && is_array ($array [0])) {
1079
            list ($this->entryArray, $this->totalNumber) = $array;
1080
        } else {
1081
            $this->entryArray = $array;
1082
        }
1083
    }
1084
}
1085
1086
class PageBookDetail extends Page
1087
{
1088
    public function InitializeContent ()
1089
    {
1090
        $this->book = Book::getBookById ($this->idGet);
1091
        $this->title = $this->book->title;
1092
    }
1093
}
1094
1095
class PageAbout extends Page
1096
{
1097
    public function InitializeContent ()
1098
    {
1099
        $this->title = localize ("about.title");
1100
    }
1101
}
1102
1103
class PageCustomize extends Page
1104
{
1105
    private function isChecked ($key, $testedValue = 1) {
1106
        $value = getCurrentOption ($key);
1107
        if (is_array ($value)) {
1108
            if (in_array ($testedValue, $value)) {
1109
                return "checked='checked'";
1110
            }
1111
        } else {
1112
            if ($value == $testedValue) {
1113
                return "checked='checked'";
1114
            }
1115
        }
1116
        return "";
1117
    }
1118
1119
    private function isSelected ($key, $value) {
1120
        if (getCurrentOption ($key) == $value) {
1121
            return "selected='selected'";
1122
        }
1123
        return "";
1124
    }
1125
1126
    private function getStyleList () {
1127
        $result = array ();
1128
        foreach (glob ("templates/" . getCurrentTemplate () . "/styles/style-*.css") as $filename) {
1129
            if (preg_match ('/styles\/style-(.*?)\.css/', $filename, $m)) {
1130
                array_push ($result, $m [1]);
1131
            }
1132
        }
1133
        return $result;
1134
    }
1135
1136
    public function InitializeContent ()
1137
    {
1138
        $this->title = localize ("customize.title");
1139
        $this->entryArray = array ();
1140
1141
        $ignoredBaseArray = array (PageQueryResult::SCOPE_AUTHOR,
1142
                                   PageQueryResult::SCOPE_TAG,
1143
                                   PageQueryResult::SCOPE_SERIES,
1144
                                   PageQueryResult::SCOPE_PUBLISHER,
1145
                                   PageQueryResult::SCOPE_RATING,
1146
                                   "language");
1147
1148
        $content = "";
1149
        array_push ($this->entryArray, new Entry ("Template", "",
1150
                                        "<span style='cursor: pointer;' onclick='$.cookie(\"template\", \"bootstrap\", { expires: 365 });window.location=$(\".headleft\").attr(\"href\");'>Click to switch to Bootstrap</span>", "text",
1151
                                        array ()));
1152
        if (!preg_match("/(Kobo|Kindle\/3.0|EBRD1101)/", $_SERVER['HTTP_USER_AGENT'])) {
1153
            $content .= '<select id="style" onchange="updateCookie (this);">';
1154
            foreach ($this-> getStyleList () as $filename) {
1155
                $content .= "<option value='{$filename}' " . $this->isSelected ("style", $filename) . ">{$filename}</option>";
1156
            }
1157
            $content .= '</select>';
1158
        } else {
1159
            foreach ($this-> getStyleList () as $filename) {
1160
                $content .= "<input type='radio' onchange='updateCookieFromCheckbox (this);' id='style-{$filename}' name='style' value='{$filename}' " . $this->isChecked ("style", $filename) . " /><label for='style-{$filename}'> {$filename} </label>";
1161
            }
1162
        }
1163
        array_push ($this->entryArray, new Entry (localize ("customize.style"), "",
1164
                                        $content, "text",
1165
                                        array ()));
1166
        if (!useServerSideRendering ()) {
1167
            $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="use_fancyapps" ' . $this->isChecked ("use_fancyapps") . ' />';
1168
            array_push ($this->entryArray, new Entry (localize ("customize.fancybox"), "",
1169
                                            $content, "text",
1170
                                            array ()));
1171
        }
1172
        $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]+$" />';
1173
        array_push ($this->entryArray, new Entry (localize ("customize.paging"), "",
1174
                                        $content, "text",
1175
                                        array ()));
1176
        $content = '<input type="text" onchange="updateCookie (this);" id="email" value="' . getCurrentOption ("email") . '" />';
1177
        array_push ($this->entryArray, new Entry (localize ("customize.email"), "",
1178
                                        $content, "text",
1179
                                        array ()));
1180
        $content = '<input type="checkbox" onchange="updateCookieFromCheckbox (this);" id="html_tag_filter" ' . $this->isChecked ("html_tag_filter") . ' />';
1181
        array_push ($this->entryArray, new Entry (localize ("customize.filter"), "",
1182
                                        $content, "text",
1183
                                        array ()));
1184
        $content = "";
1185
        foreach ($ignoredBaseArray as $key) {
1186
            $keyPlural = preg_replace ('/(ss)$/', 's', $key . "s");
1187
            $content .=  '<input type="checkbox" name="ignored_categories[]" onchange="updateCookieFromCheckboxGroup (this);" id="ignored_categories_' . $key . '" ' . $this->isChecked ("ignored_categories", $key) . ' > ' . localize ("{$keyPlural}.title") . '</input> ';
1188
        }
1189
1190
        array_push ($this->entryArray, new Entry (localize ("customize.ignored"), "",
1191
                                        $content, "text",
1192
                                        array ()));
1193
    }
1194
}
1195
1196
1197
abstract class Base
1198
{
1199
    const PAGE_INDEX = "index";
1200
    const PAGE_ALL_AUTHORS = "1";
1201
    const PAGE_AUTHORS_FIRST_LETTER = "2";
1202
    const PAGE_AUTHOR_DETAIL = "3";
1203
    const PAGE_ALL_BOOKS = "4";
1204
    const PAGE_ALL_BOOKS_LETTER = "5";
1205
    const PAGE_ALL_SERIES = "6";
1206
    const PAGE_SERIE_DETAIL = "7";
1207 108
    const PAGE_OPENSEARCH = "8";
1208 108
    const PAGE_OPENSEARCH_QUERY = "9";
1209 108
    const PAGE_ALL_RECENT_BOOKS = "10";
1210
    const PAGE_ALL_TAGS = "11";
1211
    const PAGE_TAG_DETAIL = "12";
1212 46
    const PAGE_BOOK_DETAIL = "13";
1213 46
    const PAGE_ALL_CUSTOMS = "14";
1214
    const PAGE_CUSTOM_DETAIL = "15";
1215
    const PAGE_ABOUT = "16";
1216 46
    const PAGE_ALL_LANGUAGES = "17";
1217 46
    const PAGE_LANGUAGE_DETAIL = "18";
1218 46
    const PAGE_CUSTOMIZE = "19";
1219 46
    const PAGE_ALL_PUBLISHERS = "20";
1220 46
    const PAGE_PUBLISHER_DETAIL = "21";
1221
    const PAGE_ALL_RATINGS = "22";
1222
    const PAGE_RATING_DETAIL = "23";
1223 45
1224 45
    const COMPATIBILITY_XML_ALDIKO = "aldiko";
1225
    
1226
    const SQL_SETTING = 'SELECT val FROM preferences WHERE key = "{0}"';
1227 4
1228 4
    private static $db = NULL;
1229 4
1230 4
    public static function isDatabaseArray () {
1231
        global $config;
1232 1
        return is_array ($config['calibre_directory']);
1233
    }
1234
    
1235
    public static function isMultipleDatabaseEnabled () {
1236 5
    	return (self::isDatabaseArray () || VirtualLib::isVLEnabled());
1237 5
    }
1238 5
1239 5
    public static function useAbsolutePath () {
1240
        global $config;
1241
        $path = self::getDbDirectory();
1242
        return preg_match ('/^\//', $path) || // Linux /
1243
               preg_match ('/^\w\:/', $path); // Windows X:
1244
    }
1245 1
1246 1
    public static function noDatabaseSelected () {
1247 1
        return self::isMultipleDatabaseEnabled() && is_null (GetUrlParam (DB));
1248 1
    }
1249 1
1250
    public static function getDbList () {
1251
        global $config;
1252 1
        if (self::isDatabaseArray ()) {
1253 1
            return $config['calibre_directory'];
1254
        } else {
1255
            return array ("" => $config['calibre_directory']);
1256
        }
1257
    }
1258 90
1259 90
    public static function getDbNameList () {
1260 90
        global $config;
1261 9
        if (self::isDatabaseArray ()) {
1262 9
            return array_keys ($config['calibre_directory']);
1263
        } else {
1264
            return array ("");
1265 9
        }
1266 9
    }
1267
1268 81
    public static function getDbName ($database = NULL) {
1269
        global $config;
1270
        if (self::isDatabaseArray ()) {
1271
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1272 61
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1273 61
                return self::error ($database);
1274
            }
1275
            $array = array_keys ($config['calibre_directory']);
1276 2
            return  $array[$database];
1277 2
        }
1278
        return "";
1279
    }
1280 2
1281
    public static function getDbDirectory ($database = NULL) {
1282
        global $config;
1283 126
        if (self::isDatabaseArray ()) {
1284 126
            if (is_null ($database)) $database = GetUrlParam (DB, 0);
1285
            if (!is_null($database) && !preg_match('/^\d+$/', $database)) {
1286 61
                return self::error ($database);
1287 60
            }
1288 60
            $array = array_values ($config['calibre_directory']);
1289 7
            return  $array[$database];
1290 7
        }
1291 60
        return $config['calibre_directory'];
1292 2
    }
1293
1294 61
1295 2
    public static function getDbFileName ($database = NULL) {
1296
        return self::getDbDirectory ($database) .'metadata.db';
1297 60
    }
1298 125
1299
    private static function error ($database) {
1300
        if (php_sapi_name() != "cli") {
1301 4
            header("location: checkconfig.php?err=1");
1302 4
        }
1303 3
        throw new Exception("Database <{$database}> not found.");
1304 3
    }
1305 2
1306 2
    public static function getDb ($database = NULL) {
1307 1
        if (is_null (self::$db)) {
1308 1
            try {
1309
                if (is_readable (self::getDbFileName ($database))) {
1310 2
                    self::$db = new PDO('sqlite:'. self::getDbFileName ($database));
1311
                    if (useNormAndUp ()) {
1312
                        self::$db->sqliteCreateFunction ('normAndUp', 'normAndUp', 1);
1313 58
                    }
1314 58
                } else {
1315 58
                    self::error ($database);
1316
                }
1317 35
            } catch (Exception $e) {
1318 35
                self::error ($database);
1319
            }
1320
        }
1321 8
        return self::$db;
1322 8
    }
1323 7
1324 7
    public static function checkDatabaseAvailability () {
1325 8
        if (self::noDatabaseSelected ()) {
1326 8
            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...
1327 8
                self::getDb ($i);
1328 8
                self::clearDb ();
1329 8
            }
1330 8
        } else {
1331
            self::getDb ();
1332
        }
1333 35
        return true;
1334 35
    }
1335 35
1336 35
    public static function clearDb () {
1337
        self::$db = NULL;
1338 25
    }
1339 25
1340 17
    public static function executeQuerySingle ($query, $database = NULL) {
1341 17
        return self::getDb ($database)->query($query)->fetchColumn();
1342 8
    }
1343
    
1344 25
    /**
1345 25
     * Executes a sql query filtered for a virtual library. The query returns a single value;
1346 25
     * 
1347 25
     * @param string $query The sql query. A {0} indicates the space to include the filter query. 
1348 35
     * @param int $database The database id.
1349
     * @param int $virtualLib The id of the virtual library.
1350
     * @return mixed The single-value result of the query.
1351 73
     */
1352 73
    public static function executeFilteredQuerySingle ($query, $database = NULL, $virtualLib = null) {
1353
    	$query = str_format($query, VirtualLib::getVL($database, $virtualLib)->getFilterQuery());
1354 73
    	return self::getDb ($database)->query($query)->fetchColumn();
1355 7
    }
1356 7
1357 7
    public static function getCountGeneric($table, $id, $pageId, $numberOfString = NULL) {
1358
        if (!$numberOfString) {
1359 73
            $numberOfString = $table . ".alphabetical";
1360 71
        }
1361 71
        $count = self::executeFilteredQuerySingle ('select count(distinct ' . $table .'.id) from ' . Filter::getLinkedTable($table));
1362
        if ($count == 0) return NULL;
1363 73
        $entry = new Entry (localize($table . ".title"), $id,
1364 73
            str_format (localize($numberOfString, $count), $count), "text",
1365
            array ( new LinkNavigation ("?page=".$pageId)), "", $count);
1366 28
        return $entry;
1367 28
    }
1368 28
1369
    public static function getEntryArrayWithBookNumber ($query, $params, $category) {
1370
        list (, $result) = self::executeFilteredQuery($query, $params, -1);
1371 28
        $entryArray = array();
1372 28
        while ($post = $result->fetchObject ())
1373 28
        {
1374
            $instance = new $category ($post);
1375 73
            if (property_exists($post, "sort")) {
1376 73
                $title = $post->sort;
1377 73
            } else {
1378
                $title = $post->name;
1379
            }
1380
            array_push ($entryArray, new Entry ($title, $instance->getEntryId (),
1381
                str_format (localize("bookword", $post->count), $post->count), "text",
1382
                array ( new LinkNavigation ($instance->getUri ())), "", $post->count));
1383
        }
1384
        return $entryArray;
1385
    }
1386
    
1387 22
    /**
1388 22
     * Executes a sql query filtered for a virtual library.
1389 22
     * 
1390
     * @param string $query The sql query. A {0} indicates the space to include the filter query. 
1391
     * @param array $params SQL parameter
1392
     * @param int $n Page number
1393
     * @param int $database Database ID
1394
     * @param int $virtualLib ID of the virtual library
1395
     * @param int $numberPerPage Number of shown entries per page
1396
     * @return multitype:number PDOStatement
0 ignored issues
show
The doc-type multitype:number could not be parsed: Unknown type name "multitype:number" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1397
     */
1398
    public static function executeFilteredQuery($query, $params, $n, $database = NULL, $virtualLib = NULL,$numberPerPage = NULL) {
1399
    	$totalResult = -1;
1400
    
1401
    	$query = str_format($query, VirtualLib::getVL($database, $virtualLib)->getFilterQuery());
1402
    	
1403
    	if (useNormAndUp ()) {
1404
    		$query = preg_replace("/upper/", "normAndUp", $query);
1405
    	}
1406
    
1407
    	if (is_null ($numberPerPage)) {
1408
    		$numberPerPage = getCurrentOption ("max_item_per_page");
1409
    	}
1410
    
1411
    	if ($numberPerPage != -1 && $n != -1)
1412
    	{
1413
    		// First check total number of results
1414
    		$result = self::getDb ($database)->prepare (str_format ("select count(*) from ({0})", $query));
1415
    		$result->execute ($params);
1416
    		$totalResult = $result->fetchColumn ();
1417
    
1418
    		// Next modify the query and params
1419
    		$query .= " limit ?, ?";
1420
    		array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage);
1421
    	}
1422
    
1423
    	$result = self::getDb ($database)->prepare($query);
1424
    	$result->execute ($params);
1425
    	return array ($totalResult, $result);
1426
    }
1427
1428
    public static function executeQuery($query, $columns, $filter, $params, $n, $database = NULL, $numberPerPage = NULL) {
1429
        $totalResult = -1;
1430
1431
        if (useNormAndUp ()) {
1432
            $query = preg_replace("/upper/", "normAndUp", $query);
1433
            $columns = preg_replace("/upper/", "normAndUp", $columns);
1434
        }
1435
1436
        if (is_null ($numberPerPage)) {
1437
            $numberPerPage = getCurrentOption ("max_item_per_page");
1438
        }
1439
1440
        if ($numberPerPage != -1 && $n != -1)
1441
        {
1442
            // First check total number of results
1443
            $result = self::getDb ($database)->prepare (str_format ($query, "count(*)", $filter));
1444
            $result->execute ($params);
1445
            $totalResult = $result->fetchColumn ();
1446
1447
            // Next modify the query and params
1448
            $query .= " limit ?, ?";
1449
            array_push ($params, ($n - 1) * $numberPerPage, $numberPerPage);
1450
        }
1451
1452
        $result = self::getDb ($database)->prepare(str_format ($query, $columns, $filter));
1453
        $result->execute ($params);
1454
        return array ($totalResult, $result);
1455
    }
1456
1457
    /**
1458
     * Gets a calibre setting from the database.
1459
     * 
1460
     * @param string $name Name of the property
1461
     * @param int $database Database to query from
1462
     * @return string Value of the property
1463
     */
1464
    public static function getCalibreSetting($name, $database = NULL) {
1465
    	$query = str_format(self::SQL_SETTING, $name);
1466
    	return self::executeQuerySingle($query, $database);
1467
    }
1468
}
1469