Completed
Push — master ( 2cc4d6...bb97fd )
by Sébastien
03:24
created

base.php (15 issues)

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
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 11 and the first side effect is on line 9.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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
require 'config.php';
10
11
define ('VERSION', '1.0.2');
12
define ('DB', 'db');
13
date_default_timezone_set($config['default_timezone']);
14
15
16
function useServerSideRendering()
17
{
18 3
    global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
19 3
    return preg_match('/' . $config['cops_server_side_render'] . '/', $_SERVER['HTTP_USER_AGENT']);
20
}
21
22
function serverSideRender($data)
23
{
24
    // Get the templates
25 2
    $theme = getCurrentTemplate ();
26 2
    $header = file_get_contents('templates/' . $theme . '/header.html');
27 2
    $footer = file_get_contents('templates/' . $theme . '/footer.html');
28 2
    $main = file_get_contents('templates/' . $theme . '/main.html');
29 2
    $bookdetail = file_get_contents('templates/' . $theme . '/bookdetail.html');
30 2
    $page = file_get_contents('templates/' . $theme . '/page.html');
31
32
    // Generate the function for the template
33 2
    $template = new doT ();
34 2
    $dot = $template->template ($page, array ('bookdetail' => $bookdetail,
35 2
                                              'header' => $header,
36 2
                                              'footer' => $footer,
37 2
                                              'main' => $main));
38
    // If there is a syntax error in the function created
39
    // $dot will be equal to FALSE
40 2
    if (!$dot) {
41
        return FALSE;
42
    }
43
    // Execute the template
44 2
    if (!empty ($data)) {
45
        return $dot ($data);
46
    }
47
48 2
    return NULL;
49
}
50
51
function getQueryString()
52
{
53 18
    if (isset($_SERVER['QUERY_STRING'])) {
54 16
        return $_SERVER['QUERY_STRING'];
55
    }
56 2
    return "";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
57
}
58
59
function notFound()
60
{
61
    header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
62
    header('Status: 404 Not Found');
63
64
    $_SERVER['REDIRECT_STATUS'] = 404;
65
}
66
67
function getURLParam($name, $default = NULL)
68
{
69 134
    if (!empty ($_GET) && isset($_GET[$name]) && $_GET[$name] != '') {
70 34
        return $_GET[$name];
71
    }
72 122
    return $default;
73
}
74
75
function getCurrentOption($option)
76
{
77 100
    global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
78 100
    if (isset($_COOKIE[$option])) {
79 2
        if (isset($config ['cops_' . $option]) && is_array ($config ['cops_' . $option])) {
80
            return explode (',', $_COOKIE[$option]);
81
        } else {
82 2
            return $_COOKIE[$option];
83
        }
84
    }
85 98
    if (isset($config ['cops_' . $option])) {
86 98
        return $config ['cops_' . $option];
87
    }
88
89
    return '';
90
}
91
92
function getCurrentCss()
93
{
94 2
    return 'templates/' . getCurrentTemplate () . '/styles/style-' . getCurrentOption('style') . '.css';
95
}
96
97
function getCurrentTemplate()
98
{
99 4
    return getCurrentOption ('template');
100
}
101
102
function getUrlWithVersion($url)
103
{
104 69
    return $url . '?v=' . VERSION;
105
}
106
107
function xml2xhtml($xml)
108
{
109
    return preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($m) {
110 37
        $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param');
111 37
        if (in_array($m[1], $xhtml_tags)) {
112 34
            return '<' . $m[1] . $m[2] . ' />';
113
        } else {
114 37
            return '<' . $m[1] . $m[2] . '></' . $m[1] . '>';
115
        }
116 37
    }, $xml);
117
}
118
119
function display_xml_error($error)
0 ignored issues
show
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
120
{
121
    $return = '';
122
    $return .= str_repeat('-', $error->column) . "^\n";
123
124
    switch ($error->level) {
125
        case LIBXML_ERR_WARNING:
126
            $return .= 'Warning ' . $error->code . ': ';
127
            break;
128
         case LIBXML_ERR_ERROR:
129
            $return .= 'Error ' . $error->code . ': ';
130
            break;
131
        case LIBXML_ERR_FATAL:
132
            $return .= 'Fatal Error ' . $error->code . ': ';
133
            break;
134
    }
135
136
    $return .= trim($error->message) .
137
               "\n  Line: " . $error->line .
138
               "\n  Column: " . $error->column;
139
140
    if ($error->file) {
141
        $return .= "\n  File: " . $error->file;
142
    }
143
144
    return "$return\n\n--------------------------------------------\n\n";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $return instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
145
}
146
147
function are_libxml_errors_ok()
0 ignored issues
show
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
148
{
149 37
    $errors = libxml_get_errors();
150
151 37
    foreach ($errors as $error) {
152
        if ($error->code == 801) return false;
153 37
    }
154 37
    return true;
155
}
156
157
function html2xhtml($html)
158
{
159 37
    $doc = new DOMDocument();
160 37
    libxml_use_internal_errors(true);
161
162 37
    $doc->loadHTML('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>' .
163 37
                        $html  . '</body></html>'); // Load the HTML
164 37
    $output = $doc->saveXML($doc->documentElement); // Transform to an Ansi xml stream
165 37
    $output = xml2xhtml($output);
166 37
    if (preg_match ('#<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></meta></head><body>(.*)</body></html>#ms', $output, $matches)) {
167 37
        $output = $matches [1]; // Remove <html><body>
168 37
    }
169
    /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
170
    // In case of error with summary, use it to debug
171
    $errors = libxml_get_errors();
172
173
    foreach ($errors as $error) {
174
        $output .= display_xml_error($error);
175
    }
176
    */
177
178 37
    if (!are_libxml_errors_ok ()) $output = 'HTML code not valid.';
179
180 37
    libxml_use_internal_errors(false);
181 37
    return $output;
182
}
183
184
/**
185
 * This method is a direct copy-paste from
186
 * http://tmont.com/blargh/2010/1/string-format-in-php
187
 */
188
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...
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
189
{
190 116
    $args = func_get_args();
191 116
    $format = array_shift($args);
192
193 116
    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
194 116
    $offset = 0;
195 116
    foreach ($matches[1] as $data) {
196 116
        $i = $data[0];
197 116
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
198 116
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
199 116
    }
200
201 116
    return $format;
202
}
203
204
/**
205
 * Get all accepted languages from the browser and put them in a sorted array
206
 * languages id are normalized : fr-fr -> fr_FR
207
 * @return array of languages
208
 */
209
function getAcceptLanguages()
210
{
211 16
    $langs = array();
212
213 16
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
214
        // break up string into pieces (languages and q factors)
215 16
        $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
216 16 View Code Duplication
        if (preg_match('/^(\w{2})-\w{2}$/', $accept, $matches)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
            // Special fix for IE11 which send fr-FR and nothing else
218 3
            $accept = $accept . ',' . $matches[1] . ';q=0.8';
219 3
        }
220 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);
221
222 16
        if (count($lang_parse[1])) {
223 16
            $langs = array();
224 16
            foreach ($lang_parse[1] as $lang) {
225
                // Format the language code (not standard among browsers)
226 16
                if (strlen($lang) == 5) {
227 11
                    $lang = str_replace('-', '_', $lang);
228 11
                    $splitted = preg_split('/_/', $lang);
229 11
                    $lang = $splitted[0] . '_' . strtoupper($splitted[1]);
230 11
                }
231 16
                array_push($langs, $lang);
232 16
            }
233
            // create a list like "en" => 0.8
234 16
            $langs = array_combine($langs, $lang_parse[4]);
235
236
            // set default to 1 for any without q factor
237 16
            foreach ($langs as $lang => $val) {
238 16
                if ($val === '') $langs[$lang] = 1;
239 16
            }
240
241
            // sort list based on value
242 16
            arsort($langs, SORT_NUMERIC);
243 16
        }
244 16
    }
245
246 16
    return $langs;
247
}
248
249
/**
250
 * Find the best translation file possible based on the accepted languages
251
 * @return array of language and language file
252
 */
253
function getLangAndTranslationFile()
254
{
255 17
    global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
256 17
    $langs = array();
257 17
    $lang = 'en';
258 17
    if (!empty($config['cops_language'])) {
259
        $lang = $config['cops_language'];
260
    }
261 17
    elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
262 16
        $langs = getAcceptLanguages();
263 16
    }
264
    //echo var_dump($langs);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
265 17
    $lang_file = NULL;
266 17
    foreach ($langs as $language => $val) {
267 16
        $temp_file = dirname(__FILE__). '/lang/Localization_' . $language . '.json';
268 16
        if (file_exists($temp_file)) {
269 16
            $lang = $language;
270 16
            $lang_file = $temp_file;
271 16
            break;
272
        }
273 17
    }
274 17
    if (empty ($lang_file)) {
275 3
        $lang_file = dirname(__FILE__). '/lang/Localization_' . $lang . '.json';
276 3
    }
277 17
    return array($lang, $lang_file);
278
}
279
280
/**
281
 * This method is based on this page
282
 * http://www.mind-it.info/2010/02/22/a-simple-approach-to-localization-in-php/
283
 */
284
function localize($phrase, $count=-1, $reset=false)
285
{
286 136
    global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
287 136
    if ($count == 0)
288 136
        $phrase .= '.none';
289 136
    if ($count == 1)
290 136
        $phrase .= '.one';
291 136
    if ($count > 1)
292 136
        $phrase .= '.many';
293
294
    /* Static keyword is used to ensure the file is loaded only once */
295 136
    static $translations = NULL;
296 136
    if ($reset) {
297 16
        $translations = NULL;
298 16
    }
299
    /* If no instance of $translations has occured load the language file */
300 136
    if (is_null($translations)) {
301 17
        $lang_file_en = NULL;
302 17
        list ($lang, $lang_file) = getLangAndTranslationFile();
303 17
        if ($lang != 'en') {
304 1
            $lang_file_en = dirname(__FILE__). '/lang/' . 'Localization_en.json';
305 1
        }
306
307 17
        $lang_file_content = file_get_contents($lang_file);
308
        /* Load the language file as a JSON object and transform it into an associative array */
309 17
        $translations = json_decode($lang_file_content, true);
310
311
        /* Clean the array of all unfinished translations */
312 17
        foreach (array_keys ($translations) as $key) {
313 17
            if (preg_match ('/^##TODO##/', $key)) {
314
                unset ($translations [$key]);
315
            }
316 17
        }
317 17
        if (!is_null($lang_file_en)) {
318 1
            $lang_file_content = file_get_contents($lang_file_en);
319 1
            $translations_en = json_decode($lang_file_content, true);
320 1
            $translations = array_merge ($translations_en, $translations);
321 1
        }
322 17
    }
323 136
    if (array_key_exists ($phrase, $translations)) {
324 136
        return $translations[$phrase];
325
    }
326 3
    return $phrase;
327
}
328
329
function addURLParameter($urlParams, $paramName, $paramValue)
330
{
331 61
    if (empty ($urlParams)) {
332 51
        $urlParams = '';
333 51
    }
334 61
    $start = '';
335 61
    if (preg_match ('#^\?(.*)#', $urlParams, $matches)) {
336 15
        $start = '?';
337 15
        $urlParams = $matches[1];
338 15
    }
339 61
    $params = array();
340 61
    parse_str($urlParams, $params);
341 61
    if (empty ($paramValue) && $paramValue != 0) {
342
        unset ($params[$paramName]);
343
    } else {
344 61
        $params[$paramName] = $paramValue;
345
    }
346 61
    return $start . http_build_query($params);
347
}
348
349
function useNormAndUp()
350
{
351 144
    global $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
352 144
    return $config ['cops_normalized_search'] == '1';
353
}
354
355
function normalizeUtf8String($s)
356
{
357 8
    include_once 'transliteration.php';
358 8
    return _transliteration_process($s);
359
}
360
361
function normAndUp($s)
362
{
363 7
    return mb_strtoupper(normalizeUtf8String($s), 'UTF-8');
364
}
365