Issues (982)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/Book.php (1 issue)

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
// Silly thing because PHP forbid string concatenation in class const
10
define ('SQL_BOOKS_LEFT_JOIN', 'left outer join comments on comments.book = books.id
11
                                left outer join books_ratings_link on books_ratings_link.book = books.id
12
                                left outer join ratings on books_ratings_link.rating = ratings.id ');
13
define ('SQL_BOOKS_ALL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . ' order by books.sort ');
14
define ('SQL_BOOKS_BY_PUBLISHER', 'select {0} from books_publishers_link, books ' . SQL_BOOKS_LEFT_JOIN . '
15
                                                    where books_publishers_link.book = books.id and publisher = ? {1} order by publisher');
16
define ('SQL_BOOKS_BY_FIRST_LETTER', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
17
                                                    where upper (books.sort) like ? order by books.sort');
18
define ('SQL_BOOKS_BY_AUTHOR', 'select {0} from books_authors_link, books ' . SQL_BOOKS_LEFT_JOIN . '
19
                                                    left outer join books_series_link on books_series_link.book = books.id
20
                                                    where books_authors_link.book = books.id and author = ? {1} order by series desc, series_index asc, pubdate asc');
21
define ('SQL_BOOKS_BY_SERIE', 'select {0} from books_series_link, books ' . SQL_BOOKS_LEFT_JOIN . '
22
                                                    where books_series_link.book = books.id and series = ? {1} order by series_index');
23
define ('SQL_BOOKS_BY_TAG', 'select {0} from books_tags_link, books ' . SQL_BOOKS_LEFT_JOIN . '
24
                                                    where books_tags_link.book = books.id and tag = ? {1} order by sort');
25
define ('SQL_BOOKS_BY_LANGUAGE', 'select {0} from books_languages_link, books ' . SQL_BOOKS_LEFT_JOIN . '
26
                                                    where books_languages_link.book = books.id and lang_code = ? {1} order by sort');
27
define ('SQL_BOOKS_BY_CUSTOM', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
28
                                                    where {2}.book = books.id and {2}.{3} = ? {1} order by sort');
29
define ('SQL_BOOKS_BY_CUSTOM_BOOL_TRUE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
30
                                                    where {2}.book = books.id and {2}.value = 1 {1} order by sort');
31
define ('SQL_BOOKS_BY_CUSTOM_BOOL_FALSE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
32
                                                    where {2}.book = books.id and {2}.value = 0 {1} order by sort');
33
define ('SQL_BOOKS_BY_CUSTOM_BOOL_NULL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
34
                                                    where books.id not in (select book from {2}) {1} order by sort');
35
define ('SQL_BOOKS_BY_CUSTOM_RATING', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
36
                                                    left join {2} on {2}.book = books.id
37
                                                    left join {3} on {3}.id = {2}.{4}
38
                                                    where {3}.value = ?  order by sort');
39
define ('SQL_BOOKS_BY_CUSTOM_RATING_NULL', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
40
								                    left join {2} on {2}.book = books.id
41
								                    left join {3} on {3}.id = {2}.{4}
42
                                                    where ((books.id not in (select {2}.book from {2})) or ({3}.value = 0)) {1} order by sort');
43
define ('SQL_BOOKS_BY_CUSTOM_DATE', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
44
                                                    where {2}.book = books.id and date({2}.value) = ? {1} order by sort');
45
define ('SQL_BOOKS_BY_CUSTOM_DIRECT', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
46
                                                    where {2}.book = books.id and {2}.value = ? {1} order by sort');
47
define ('SQL_BOOKS_BY_CUSTOM_DIRECT_ID', 'select {0} from {2}, books ' . SQL_BOOKS_LEFT_JOIN . '
48
                                                    where {2}.book = books.id and {2}.id = ? {1} order by sort');
49
define ('SQL_BOOKS_QUERY', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
50
                                                    where (
51
                                                    exists (select null from authors, books_authors_link where book = books.id and author = authors.id and authors.name like ?) or
52
                                                    exists (select null from tags, books_tags_link where book = books.id and tag = tags.id and tags.name like ?) or
53
                                                    exists (select null from series, books_series_link on book = books.id and books_series_link.series = series.id and series.name like ?) or
54
                                                    exists (select null from publishers, books_publishers_link where book = books.id and books_publishers_link.publisher = publishers.id and publishers.name like ?) or
55
                                                    title like ?) {1} order by books.sort');
56
define ('SQL_BOOKS_RECENT', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
57
                                                    where 1=1 {1} order by timestamp desc limit ');
58
define ('SQL_BOOKS_BY_RATING', 'select {0} from books ' . SQL_BOOKS_LEFT_JOIN . '
59
                                                    where books_ratings_link.book = books.id and ratings.id = ? {1} order by sort');
60
61
class Book
62
{
63
    const ALL_BOOKS_UUID = 'urn:uuid';
64
    const ALL_BOOKS_ID = 'cops:books';
65
    const ALL_RECENT_BOOKS_ID = 'cops:recentbooks';
66
    const BOOK_COLUMNS = 'books.id as id, books.title as title, text as comment, path, timestamp, pubdate, series_index, uuid, has_cover, ratings.rating';
67
68
    const SQL_BOOKS_LEFT_JOIN = SQL_BOOKS_LEFT_JOIN;
69
    const SQL_BOOKS_ALL = SQL_BOOKS_ALL;
70
    const SQL_BOOKS_BY_PUBLISHER = SQL_BOOKS_BY_PUBLISHER;
71
    const SQL_BOOKS_BY_FIRST_LETTER = SQL_BOOKS_BY_FIRST_LETTER;
72
    const SQL_BOOKS_BY_AUTHOR = SQL_BOOKS_BY_AUTHOR;
73
    const SQL_BOOKS_BY_SERIE = SQL_BOOKS_BY_SERIE;
74
    const SQL_BOOKS_BY_TAG = SQL_BOOKS_BY_TAG;
75
    const SQL_BOOKS_BY_LANGUAGE = SQL_BOOKS_BY_LANGUAGE;
76
    const SQL_BOOKS_BY_CUSTOM = SQL_BOOKS_BY_CUSTOM;
77
    const SQL_BOOKS_BY_CUSTOM_BOOL_TRUE = SQL_BOOKS_BY_CUSTOM_BOOL_TRUE;
78
    const SQL_BOOKS_BY_CUSTOM_BOOL_FALSE = SQL_BOOKS_BY_CUSTOM_BOOL_FALSE;
79
    const SQL_BOOKS_BY_CUSTOM_BOOL_NULL = SQL_BOOKS_BY_CUSTOM_BOOL_NULL;
80
    const SQL_BOOKS_BY_CUSTOM_RATING = SQL_BOOKS_BY_CUSTOM_RATING;
81
    const SQL_BOOKS_BY_CUSTOM_RATING_NULL = SQL_BOOKS_BY_CUSTOM_RATING_NULL;
82
    const SQL_BOOKS_BY_CUSTOM_DATE = SQL_BOOKS_BY_CUSTOM_DATE;
83
    const SQL_BOOKS_BY_CUSTOM_DIRECT = SQL_BOOKS_BY_CUSTOM_DIRECT;
84
    const SQL_BOOKS_BY_CUSTOM_DIRECT_ID = SQL_BOOKS_BY_CUSTOM_DIRECT_ID;
85
    const SQL_BOOKS_QUERY = SQL_BOOKS_QUERY;
86
    const SQL_BOOKS_RECENT = SQL_BOOKS_RECENT;
87
    const SQL_BOOKS_BY_RATING = SQL_BOOKS_BY_RATING;
88
89
    const BAD_SEARCH = 'QQQQQ';
90
91
    public $id;
92
    public $title;
93
    public $timestamp;
94
    public $pubdate;
95
    public $path;
96
    public $uuid;
97
    public $hasCover;
98
    public $relativePath;
99
    public $seriesIndex;
100
    public $comment;
101
    public $rating;
102
    public $datas = NULL;
103
    public $authors = NULL;
104
    public $publisher = NULL;
105
    public $serie = NULL;
106
    public $tags = NULL;
107
    public $languages = NULL;
108
    public $format = array ();
109
110
111 78
    public function __construct($line) {
112 78
        $this->id = $line->id;
113 78
        $this->title = $line->title;
114 78
        $this->timestamp = strtotime($line->timestamp);
115 78
        $this->pubdate = $line->pubdate;
116 78
        $this->path = Base::getDbDirectory() . $line->path;
117 78
        $this->relativePath = $line->path;
118 78
        $this->seriesIndex = $line->series_index;
119 78
        $this->comment = $line->comment;
120 78
        $this->uuid = $line->uuid;
121 78
        $this->hasCover = $line->has_cover;
122 78
        if (!file_exists($this->getFilePath('jpg'))) {
123
            // double check
124 44
            $this->hasCover = 0;
125 44
        }
126 78
        $this->rating = $line->rating;
127 78
    }
128
129 42
    public function getEntryId() {
130 42
        return self::ALL_BOOKS_UUID.':'.$this->uuid;
131
    }
132
133 4
    public static function getEntryIdByLetter ($startingLetter) {
134 4
        return self::ALL_BOOKS_ID.':letter:'.$startingLetter;
135
    }
136
137 3
    public function getUri () {
138 3
        return '?page='.Base::PAGE_BOOK_DETAIL.'&id=' . $this->id;
139
    }
140
141 3
    public function getDetailUrl () {
142 3
        $urlParam = $this->getUri();
143 3 View Code Duplication
        if (!is_null(GetUrlParam(DB))) $urlParam = addURLParameter($urlParam, DB, GetUrlParam (DB));
144 3
        return 'index.php' . $urlParam;
145
    }
146
147 43
    public function getTitle () {
148 43
        return $this->title;
149
    }
150
151
    /* Other class (author, series, tag, ...) initialization and accessors */
152
153
    /**
154
     * @return Author[]
155
     */
156 49
    public function getAuthors () {
157 49
        if (is_null($this->authors)) {
158 49
            $this->authors = Author::getAuthorByBookId($this->id);
159 49
        }
160 49
        return $this->authors;
161
    }
162
163
    public function getAuthorsName () {
164
        return implode(', ', array_map(function ($author) { return $author->name; }, $this->getAuthors()));
165
    }
166
167
    public function getAuthorsSort () {
168
        return implode(', ', array_map(function ($author) { return $author->sort; }, $this->getAuthors()));
169
    }
170
171 5
    public function getPublisher () {
172 5
        if (is_null($this->publisher)) {
173 5
            $this->publisher = Publisher::getPublisherByBookId($this->id);
174 5
        }
175 5
        return $this->publisher;
176
    }
177
178
    /**
179
     * @return Serie
180
     */
181 48
    public function getSerie() {
182 48
        if (is_null($this->serie)) {
183 48
            $this->serie = Serie::getSerieByBookId($this->id);
184 48
        }
185 48
        return $this->serie;
186
    }
187
188
    /**
189
     * @return string
190
     */
191 10
    public function getLanguages() {
192 10
        $lang = array();
193 10
        $result = Base::getDb()->prepare('select languages.lang_code
194
                from books_languages_link, languages
195
                where books_languages_link.lang_code = languages.id
196
                and book = ?
197 10
                order by item_order');
198 10
        $result->execute(array($this->id));
199 10
        while ($post = $result->fetchObject())
200
        {
201 10
            array_push($lang, Language::getLanguageString($post->lang_code));
202 10
        }
203 10
        return implode(', ', $lang);
204
    }
205
206
    /**
207
     * @return Tag[]
208
     */
209 10
    public function getTags() {
210 10
        if (is_null ($this->tags)) {
211 10
            $this->tags = array();
212
213 10
            $result = Base::getDb()->prepare('select tags.id as id, name
214
                from books_tags_link, tags
215
                where tag = tags.id
216
                and book = ?
217 10
                order by name');
218 10
            $result->execute(array($this->id));
219 10
            while ($post = $result->fetchObject())
220
            {
221 9
                array_push($this->tags, new Tag($post));
222 9
            }
223 10
        }
224 10
        return $this->tags;
225
    }
226
227
    public function getTagsName() {
228
        return implode(', ', array_map(function ($tag) { return $tag->name; }, $this->getTags()));
229
    }
230
231
    /**
232
     * @return Data[]
233
     */
234 62
    public function getDatas()
235
    {
236 62
        if (is_null($this->datas)) {
237 62
            $this->datas = Data::getDataByBook($this);
238 62
        }
239 62
        return $this->datas;
240
    }
241
242
    /* End of other class (author, series, tag, ...) initialization and accessors */
243
244 58
    public static function getFilterString() {
245 58
        $filter = getURLParam('tag', NULL);
246 58
        if (empty($filter)) return '';
247
248 3
        $exists = true;
249 3
        if (preg_match("/^!(.*)$/", $filter, $matches)) {
250 1
            $exists = false;
251 1
            $filter = $matches[1];
252 1
        }
253
254 3
        $result = 'exists (select null from books_tags_link, tags where books_tags_link.book = books.id and books_tags_link.tag = tags.id and tags.name = "' . $filter . '")';
255
256 3
        if (!$exists) {
257 1
            $result = 'not ' . $result;
258 1
        }
259
260 3
        return 'and ' . $result;
261
    }
262
263 4
    public function GetMostInterestingDataToSendToKindle()
0 ignored issues
show
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
264
    {
265 4
        $bestFormatForKindle = array('EPUB', 'PDF', 'AZW3', 'MOBI');
266 4
        $bestRank = -1;
267 4
        $bestData = NULL;
268 4
        foreach ($this->getDatas() as $data) {
269 4
            $key = array_search($data->format, $bestFormatForKindle);
270 4
            if ($key !== false && $key > $bestRank) {
271 4
                $bestRank = $key;
272 4
                $bestData = $data;
273 4
            }
274 4
        }
275 4
        return $bestData;
276
    }
277
278 3
    public function getDataById($idData)
279
    {
280
        $reduced = array_filter($this->getDatas(), function ($data) use ($idData) {
281 3
            return $data->id == $idData;
282 3
        });
283 3
        return reset($reduced);
284
    }
285
286 8
    public function getRating() {
287 8
        if (is_null($this->rating) || $this->rating == 0) {
288 3
            return '';
289
        }
290 5
        $retour = '';
291 5
        for ($i = 0; $i < $this->rating / 2; $i++) {
292 5
            $retour .= '&#9733;';
293 5
        }
294 5
        for ($i = 0; $i < 5 - $this->rating / 2; $i++) {
295 3
            $retour .= '&#9734;';
296 3
        }
297 5
        return $retour;
298
    }
299
300 15
    public function getPubDate() {
301 15
        if (empty ($this->pubdate)) {
302 2
            return '';
303
        }
304 13
        $dateY = (int) substr($this->pubdate, 0, 4);
305 13
        if ($dateY > 102) {
306 12
            return str_pad($dateY, 4, '0', STR_PAD_LEFT);
307
        }
308 1
        return '';
309
    }
310
311 43
    public function getComment($withSerie = true) {
312 43
        $addition = '';
313 43
        $se = $this->getSerie ();
314 43
        if (!is_null ($se) && $withSerie) {
315 38
            $addition = $addition . '<strong>' . localize('content.series') . '</strong>' . str_format(localize('content.series.data'), $this->seriesIndex, htmlspecialchars($se->name)) . "<br />\n";
316 38
        }
317 43
        if (preg_match('/<\/(div|p|a|span)>/', $this->comment))
318 43
        {
319 37
            return $addition . html2xhtml($this->comment);
320
        }
321
        else
322
        {
323 31
            return $addition . htmlspecialchars($this->comment);
324
        }
325
    }
326
327
    public function getDataFormat($format) {
328 12
        $reduced = array_filter($this->getDatas(), function ($data) use ($format) {
329 12
            return $data->format == $format;
330 12
        });
331 12
        return reset($reduced);
332
    }
333
334 78
    public function getFilePath($extension, $idData = NULL, $relative = false)
335
    {
336 78
        if ($extension == 'jpg')
337 78
        {
338 78
            $file = 'cover.jpg';
339 78
        }
340
        else
341
        {
342 2
            $data = $this->getDataById($idData);
343 2
            if (!$data) return NULL;
344 2
            $file = $data->name . '.' . strtolower($data->format);
345
        }
346
347
        if ($relative)
348 78
        {
349 3
            return $this->relativePath.'/'.$file;
350
        }
351
        else
352
        {
353 78
            return $this->path.'/'.$file;
354
        }
355
    }
356
357
    public function getUpdatedEpub($idData)
358
    {
359
        global $config;
360
        $data = $this->getDataById($idData);
361
362
        try
363
        {
364
            $epub = new EPub($data->getLocalPath());
365
366
            $epub->Title($this->title);
367
            $authorArray = array();
368
            foreach ($this->getAuthors() as $author) {
369
                $authorArray[$author->sort] = $author->name;
370
            }
371
            $epub->Authors($authorArray);
372
            $epub->Language($this->getLanguages());
373
            $epub->Description ($this->getComment(false));
374
            $epub->Subjects($this->getTagsName());
375
            $epub->Cover2($this->getFilePath('jpg'), 'image/jpeg');
376
            $epub->Calibre($this->uuid);
377
            $se = $this->getSerie();
378
            if (!is_null($se)) {
379
                $epub->Serie($se->name);
380
                $epub->SerieIndex($this->seriesIndex);
381
            }
382
            if ($config['cops_provide_kepub'] == '1'  && preg_match('/Kobo/', $_SERVER['HTTP_USER_AGENT'])) {
383
                $epub->updateForKepub();
384
            }
385
            $epub->download($data->getUpdatedFilenameEpub());
386
        }
387
        catch (Exception $e)
388
        {
389
            echo 'Exception : ' . $e->getMessage();
390
        }
391
    }
392
393 3
    public function getThumbnail($width, $height, $outputfile = NULL) {
394 3
        if (is_null($width) && is_null($height)) {
395 1
            return false;
396
        }
397
398 3
        $file = $this->getFilePath('jpg');
399
        // get image size
400 3
        if ($size = GetImageSize($file)) {
401 3
            $w = $size[0];
402 3
            $h = $size[1];
403
            //set new size
404 3
            if (!is_null($width)) {
405 2
                $nw = $width;
406 2
                if ($nw >= $w) { return false; }
407 1
                $nh = ($nw*$h)/$w;
408 1
            } else {
409 2
                $nh = $height;
410 2
                if ($nh >= $h) { return false; }
411 1
                $nw = ($nh*$w)/$h;
412
            }
413 2
        } else {
414
            return false;
415
        }
416
417
        //draw the image
418 2
        $src_img = imagecreatefromjpeg($file);
419 2
        $dst_img = imagecreatetruecolor($nw,$nh);
420 2
        imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nw, $nh, $w, $h);//resizing the image
421 2
        imagejpeg($dst_img,$outputfile,80);
422 2
        imagedestroy($src_img);
423 2
        imagedestroy($dst_img);
424
425 2
        return true;
426
    }
427
428 44
    public function getLinkArray ()
429
    {
430 44
        $linkArray = array();
431
432 44
        if ($this->hasCover)
433 44
        {
434 18
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_IMAGE_TYPE, 'cover.jpg', NULL));
435
436 18
            array_push($linkArray, Data::getLink($this, 'jpg', 'image/jpeg', Link::OPDS_THUMBNAIL_TYPE, 'cover.jpg', NULL));
437 18
        }
438
439 44
        foreach ($this->getDatas() as $data)
440
        {
441 44
            if ($data->isKnownType())
442 44
            {
443 44
                array_push($linkArray, $data->getDataLink(Link::OPDS_ACQUISITION_TYPE, $data->format));
444 44
            }
445 44
        }
446
447 44
        foreach ($this->getAuthors() as $author) {
448
            /* @var $author Author */
449 44
            array_push($linkArray, new LinkNavigation($author->getUri(), 'related', str_format(localize('bookentry.author'), localize('splitByLetter.book.other'), $author->name)));
450 44
        }
451
452 44
        $serie = $this->getSerie();
453 44
        if (!is_null ($serie)) {
454 41
            array_push($linkArray, new LinkNavigation($serie->getUri(), 'related', str_format(localize('content.series.data'), $this->seriesIndex, $serie->name)));
455 41
        }
456
457 44
        return $linkArray;
458
    }
459
460
461 41
    public function getEntry() {
462 41
        return new EntryBook($this->getTitle(), $this->getEntryId(),
463 41
            $this->getComment(), 'text/html',
464 41
            $this->getLinkArray(), $this);
465
    }
466
467 3
    public static function getBookCount($database = NULL) {
468 3
        return Base::executeQuerySingle('select count(*) from books', $database);
469
    }
470
471 21
    public static function getCount() {
472 21
        global $config;
473 21
        $nBooks = Base::executeQuerySingle('select count(*) from books');
474 21
        $result = array();
475 21
        $entry = new Entry(localize('allbooks.title'),
476 21
                          self::ALL_BOOKS_ID,
477 21
                          str_format(localize('allbooks.alphabetical', $nBooks), $nBooks), 'text',
478 21
                          array(new LinkNavigation('?page='.Base::PAGE_ALL_BOOKS)), '', $nBooks);
479 21
        array_push($result, $entry);
480 21
        if ($config['cops_recentbooks_limit'] > 0) {
481 21
            $entry = new Entry(localize('recent.title'),
482 21
                              self::ALL_RECENT_BOOKS_ID,
483 21
                              str_format(localize('recent.list'), $config['cops_recentbooks_limit']), 'text',
484 21
                              array ( new LinkNavigation ('?page='.Base::PAGE_ALL_RECENT_BOOKS)), '', $config['cops_recentbooks_limit']);
485 21
            array_push($result, $entry);
486 21
        }
487 21
        return $result;
488
    }
489
490 8
    public static function getBooksByAuthor($authorId, $n) {
491 8
        return self::getEntryArray(self::SQL_BOOKS_BY_AUTHOR, array($authorId), $n);
492
    }
493
494 1
    public static function getBooksByRating($ratingId, $n) {
495 1
        return self::getEntryArray(self::SQL_BOOKS_BY_RATING, array($ratingId), $n);
496
    }
497
498 2
    public static function getBooksByPublisher($publisherId, $n) {
499 2
        return self::getEntryArray(self::SQL_BOOKS_BY_PUBLISHER, array($publisherId), $n);
500
    }
501
502 2
    public static function getBooksBySeries($serieId, $n) {
503 2
        return self::getEntryArray(self::SQL_BOOKS_BY_SERIE, array($serieId), $n);
504
    }
505
506 2
    public static function getBooksByTag($tagId, $n) {
507 2
        return self::getEntryArray(self::SQL_BOOKS_BY_TAG, array($tagId), $n);
508
    }
509
510 2
    public static function getBooksByLanguage($languageId, $n) {
511 2
        return self::getEntryArray(self::SQL_BOOKS_BY_LANGUAGE, array($languageId), $n);
512
    }
513
514
    /**
515
     * @param $customColumn CustomColumn
516
     * @param $id integer
517
     * @param $n integer
518
     * @return array
519
     */
520 4
    public static function getBooksByCustom($customColumn, $id, $n) {
521 4
        list($query, $params) = $customColumn->getQuery($id);
522
523 4
        return self::getEntryArray($query, $params, $n);
524
    }
525
526 37
    public static function getBookById($bookId) {
527 37
        $result = Base::getDb()->prepare('select ' . self::BOOK_COLUMNS . '
528 37
from books ' . self::SQL_BOOKS_LEFT_JOIN . '
529 37
where books.id = ?');
530 37
        $result->execute(array($bookId));
531 37
        while ($post = $result->fetchObject())
532
        {
533 36
            $book = new Book($post);
534 36
            return $book;
535
        }
536 1
        return NULL;
537
    }
538
539 1
    public static function getBookByDataId($dataId) {
540 1
        $result = Base::getDb()->prepare('select ' . self::BOOK_COLUMNS . ', data.name, data.format
541 1
from data, books ' . self::SQL_BOOKS_LEFT_JOIN . '
542 1
where data.book = books.id and data.id = ?');
543 1
        $result->execute(array($dataId));
544 1
        while ($post = $result->fetchObject())
545
        {
546 1
            $book = new Book($post);
547 1
            $data = new Data($post, $book);
548 1
            $data->id = $dataId;
549 1
            $book->datas = array($data);
550 1
            return $book;
551
        }
552
        return NULL;
553
    }
554
555 2
    public static function getBooksByQuery($query, $n, $database = NULL, $numberPerPage = NULL) {
556 2
        $i = 0;
557 2
        $critArray = array();
558 2
        foreach (array(PageQueryResult::SCOPE_AUTHOR,
559 2
                       PageQueryResult::SCOPE_TAG,
560 2
                       PageQueryResult::SCOPE_SERIES,
561 2
                       PageQueryResult::SCOPE_PUBLISHER,
562 2
                       PageQueryResult::SCOPE_BOOK) as $key) {
563 2
            if (in_array($key, getCurrentOption('ignored_categories')) ||
564 2
                (!array_key_exists($key, $query) && !array_key_exists('all', $query))) {
565
                $critArray[$i] = self::BAD_SEARCH;
566
            }
567
            else {
568 2
                if (array_key_exists($key, $query)) {
569
                    $critArray[$i] = $query[$key];
570
                } else {
571 2
                    $critArray[$i] = $query["all"];
572
                }
573
            }
574 2
            $i++;
575 2
        }
576 2
        return self::getEntryArray(self::SQL_BOOKS_QUERY, $critArray, $n, $database, $numberPerPage);
577
    }
578
579 1
    public static function getBooks($n) {
580 1
        list ($entryArray, $totalNumber) = self::getEntryArray(self::SQL_BOOKS_ALL , array (), $n);
581 1
        return array($entryArray, $totalNumber);
582
    }
583
584 3 View Code Duplication
    public static function getAllBooks() {
585
        /* @var $result PDOStatement */
586
587 3
        list (, $result) = Base::executeQuery('select {0}
588
from books
589
group by substr (upper (sort), 1, 1)
590 3
order by substr (upper (sort), 1, 1)', 'substr (upper (sort), 1, 1) as title, count(*) as count', self::getFilterString(), array(), -1);
591
592 3
        $entryArray = array();
593 3
        while ($post = $result->fetchObject())
594
        {
595 3
            array_push($entryArray, new Entry($post->title, Book::getEntryIdByLetter($post->title),
596 3
                str_format(localize('bookword', $post->count), $post->count), 'text',
597 3
                array(new LinkNavigation('?page='.Base::PAGE_ALL_BOOKS_LETTER.'&id='. rawurlencode($post->title))), '', $post->count));
598 3
        }
599 3
        return $entryArray;
600
    }
601
602 25
    public static function getBooksByStartingLetter($letter, $n, $database = NULL, $numberPerPage = NULL) {
603 25
        return self::getEntryArray(self::SQL_BOOKS_BY_FIRST_LETTER, array($letter . '%'), $n, $database, $numberPerPage);
604
    }
605
606 55
    public static function getEntryArray($query, $params, $n, $database = NULL, $numberPerPage = NULL) {
607
        /* @var $totalNumber integer */
608
        /* @var $result PDOStatement */
609 55
        list($totalNumber, $result) = Base::executeQuery($query, self::BOOK_COLUMNS, self::getFilterString(), $params, $n, $database, $numberPerPage);
610
611 55
        $entryArray = array();
612 55
        while ($post = $result->fetchObject())
613
        {
614 41
            $book = new Book($post);
615 41
            array_push($entryArray, $book->getEntry());
616 41
        }
617 55
        return array($entryArray, $totalNumber);
618
    }
619
620 5
    public static function getAllRecentBooks() {
621 5
        global $config;
622 5
        list ($entryArray, ) = self::getEntryArray(self::SQL_BOOKS_RECENT . $config['cops_recentbooks_limit'], array(), -1);
623 5
        return $entryArray;
624
    }
625
626
    /**
627
     * The values of all the specified columns
628
     *
629
     * @param string[] $columns
630
     * @return CustomColumn[]
631
     */
632 5
    public function getCustomColumnValues($columns, $asArray = false) {
633 5
        $result = array();
634
635 5
        foreach ($columns as $lookup) {
636 2
            $col = CustomColumnType::createByLookup($lookup);
637 2
            if (!is_null($col)) {
638 2
                $cust = $col->getCustomByBook($this);
639 2
                if (!is_null($cust)) {
640 2
                    if ($asArray) {
641 1
                        array_push($result, $cust->toArray());
642 1
                    } else {
643 1
                        array_push($result, $cust);
644
                    }
645 2
                }
646 2
            }
647 5
        }
648
649 5
        return $result;
650
    }
651
}
652