Failed Conditions
Branch master (3ce7e2)
by Nick
14:43
created

api_header()   D

Complexity

Conditions 10
Paths 21

Size

Total Lines 29
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 24
c 0
b 0
f 0
nc 21
nop 2
dl 0
loc 29
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
1 ignored issue
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 134 and the first side effect is on line 3.

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
include_once INCLUDESPATH . '../../commonlib/phplib/rabx.php';
1 ignored issue
show
Bug introduced by
The constant INCLUDESPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
4
5
# The METHODS
6
7
$methods = array(
8
    'convertURL' => array(
9
        'parameters' => array('url'),
10
        'required' => true,
11
        'help' => 'Converts a parliament.uk Hansard URL into a TheyWorkForYou one, if possible',
12
    ),
13
    'getConstituency' => array(
14
        'new' => true,
15
        'parameters' => array('name', 'postcode'),
16
        'required' => true,
17
        'help' => 'Searches for a UK Parliament constituency and returns details',
18
    ),
19
    'getConstituencies' => array(
20
        'parameters' => array('date', 'search', 'latitude', 'longitude', 'distance'),
21
        'required' => false,
22
        'help' => 'Returns list of UK Parliament constituencies',
23
    ),
24
    'getPerson' => array(
25
        'new' => true,
26
        'parameters' => array('id'),
27
        'required' => true,
28
        'help' => 'Returns main details for a person'
29
    ),
30
    'getMP' => array(
31
        'parameters' => array('id', 'constituency', 'postcode', 'always_return', 'extra'),
32
        'required' => true,
33
        'help' => 'Returns main details for an MP'
34
    ),
35
    'getMPInfo' => array(
36
        'parameters' => array('id', 'fields'),
37
        'required' => true,
38
        'help' => 'Returns extra information for a person'
39
    ),
40
    'getMPsInfo' => array(
41
        'parameters' => array('id', 'fields'),
42
        'required' => true,
43
        'help' => 'Returns extra information for one or more people'
44
    ),
45
    'getMPs' => array(
46
        'parameters' => array('party', 'date', 'search'),
47
        'required' => false,
48
        'help' => 'Returns list of MPs',
49
    ),
50
    'getLord' => array(
51
        'parameters' => array('id'),
52
        'required' => true,
53
        'help' => 'Returns details for a Lord'
54
    ),
55
    'getLords' => array(
56
        'parameters' => array('date', 'party', 'search'),
57
        'required' => false,
58
        'help' => 'Returns list of Lords',
59
    ),
60
    'getMLA' => array(
61
        'parameters' => array('id', 'constituency', 'postcode', 'always_return'),
62
        'required' => true,
63
        'help' => 'Returns details for an MLA'
64
    ),
65
    'getMLAs' => array(
66
        'parameters' => array('date', 'party', 'search'),
67
        'required' => false,
68
        'help' => 'Returns list of MLAs',
69
    ),
70
    'getMSP' => array(
71
        'parameters' => array('id', 'constituency', 'postcode', 'always_return'),
72
        'required' => true,
73
        'help' => 'Returns details for an MSP'
74
    ),
75
    'getMSPs' => array(
76
        'parameters' => array('date', 'party', 'search'),
77
        'required' => false,
78
        'help' => 'Returns list of MSPs',
79
    ),
80
    'getGeometry' => array(
81
        'new' => true,
82
        'parameters' => array('name'),
83
        'required' => true,
84
        'help' => 'Returns centre, bounding box of UK Parliament constituencies'
85
    ),
86
    'getBoundary' => array(
87
        'parameters' => array('name'),
88
        'required' => true,
89
        'help' => 'Returns boundary polygon of UK Parliament constituency'
90
    ),
91
    'getCommittee' => array(
92
        'new' => true,
93
        'parameters' => array('name', 'date'),
94
        'required' => false,
95
        'help' => 'Returns members of Select Committee',
96
    ),
97
    'getDebates' => array(
98
        'new' => true,
99
        'parameters' => array('type', 'date', 'search', 'person', 'gid', 'year', 'order', 'page', 'num'),
100
        'required' => true,
101
        'help' => 'Returns Debates (either Commons, Westminster Hall, or Lords)',
102
    ),
103
    'getWrans' => array(
104
        'parameters' => array('date', 'search', 'person', 'gid', 'year', 'order', 'page', 'num'),
105
        'required' => true,
106
        'help' => 'Returns Written Answers',
107
    ),
108
    'getWMS' => array(
109
        'parameters' => array('date', 'search', 'person', 'gid', 'year', 'order', 'page', 'num'),
110
        'required' => true,
111
        'help' => 'Returns Written Ministerial Statements',
112
    ),
113
    'getHansard' => array(
114
        'parameters' => array('search', 'person', 'order', 'page', 'num'),
115
        'required' => true,
116
        'help' => 'Returns any of the above',
117
    ),
118
    'getComments' => array(
119
        'new' => true,
120
        'parameters' => array('search', 'page', 'num', 'pid', 'start_date', 'end_date'),
121
        'required' => false,
122
        'help' => 'Returns comments'
123
    ),
124
    'getAlerts' => array(
125
        'parameters' => array('start_date', 'end_date'),
126
        'required' => true,
127
            'superuser' => true,
128
            'help' => 'Returns a summary of email alert subscriptions created between two dates'
129
    ),
130
);
131
132
# Key-related functions
133
134
function api_log_call($key) {
135
    if ($key=='DOCS') return;
136
    $ip = $_SERVER['REMOTE_ADDR'];
137
    $query = !empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
138
    $query = preg_replace('#key=[A-Za-z0-9]+&?#', '', $query);
139
    $db = new ParlDB;
140
    $db->query("INSERT INTO api_stats (api_key, ip_address, query_time, query)
141
        VALUES (:key, :ip, NOW(), :query)", array(
142
            ':key' => $key,
143
            ':ip' => $ip,
144
            ':query' => $query
145
            ));
146
}
147
148
function api_is_superuser_key($key) {
149
  $db = new ParlDB;
150
  $q = $db->query('SELECT api_key.user_id, users.status
151
               FROM   api_key, users
152
               WHERE  users.user_id = api_key.user_id
153
               AND    api_key.api_key = :key', array(
154
                ':key' => $key
155
                ));
156
  if (!$q->rows())
157
    return false;
158
  if ($q->field(0, 'status') == 'Superuser')
159
    return true;
160
  else
161
    return false;
162
}
163
164
function api_check_key($key) {
165
    $db = new ParlDB;
166
    $q = $db->query('SELECT user_id, disabled FROM api_key WHERE api_key = :key', array(
167
        ':key' => $key
168
        ));
169
    if (!$q->rows())
170
        return false;
171
    if ($q->field(0, 'disabled'))
172
        return 'disabled';
173
    return true;
174
}
175
176
# Front-end sidebar of all methods
177
178
function api_sidebar() {
179
    global $methods;
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...
180
    $sidebar = '<div class="block"><h4>API Functions</h4> <div class="blockbody"><ul>';
181
    foreach ($methods as $method => $data) {
182
        if (isset($data['superuser']) && $data['superuser']) {
183
            continue;
184
        }
185
        $style = isset($data['new']) ? ' style="border-top: solid 1px #999999;"' : '';
186
        $sidebar .= "<li$style>";
187
        $sidebar .= "<a href='" . WEBPATH . "api/docs/$method'>$method</a>";
1 ignored issue
show
Bug introduced by
The constant WEBPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
188
        $sidebar .= "<br>$data[help]</li>";
189
    }
190
    $sidebar .= '</ul></div></div>';
191
    $sidebar = array(
192
        'type' => 'html',
193
        'content' => $sidebar
194
    );
195
    return $sidebar;
196
}
197
198
# Output functions
199
200
function api_output($arr, $last_mod=null) {
201
    $output = get_http_var('output');
202
    if (!get_http_var('docs')) {
203
        $cond = api_header($output, $last_mod);
204
        if ($cond) return;
205
    }
206
    if ($output == 'xml') {
207
        $out = '<?xml version="1.0" encoding="utf-8"?>'."\n";
208
        $out .= '<twfy>' . api_output_xml($arr) . '</twfy>';
209
    } elseif ($output == 'php') {
210
        $out = api_output_php($arr);
211
    } elseif ($output == 'rabx') {
212
        $out = api_output_rabx($arr);
213
    } elseif ($output == 'json') {
214
        $out = json_encode($arr, JSON_PRETTY_PRINT);
215
    } else { # JS
216
        $out = api_output_js($arr);
217
        $callback = get_http_var('callback');
218
        if (preg_match('#^[A-Za-z0-9._[\]]+$#', $callback)) {
219
            $out = "$callback($out)";
220
        }
221
    }
222
    print $out;
223
}
224
225
function api_header($o, $last_mod=null) {
226
    if ($last_mod && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
227
        $t = cond_parse_http_date($_SERVER['HTTP_IF_MODIFIED_SINCE']);
228
        if (isset($t) && $t >= $last_mod) {
229
            header('HTTP/1.0 304 Not Modified');
230
            header('Last-Modified: ' . date('r', $last_mod));
231
            return true;
232
        }
233
    }
234
    $charset = 'utf-8';
235
    if ($o == 'xml') {
236
        $type = 'text/xml';
237
    } elseif ($o == 'php') {
238
        $type = 'text/php';
239
    } elseif ($o == 'rabx') {
240
        $type = 'application/octet-stream';
241
    } elseif ($o == 'json') {
242
        header('Access-Control-Allow-Origin: *');
243
        $type = 'application/json';
244
    } else {
245
        header('Access-Control-Allow-Origin: *');
246
        $charset = 'iso-8859-1';
247
        $type = 'text/javascript';
248
    }
249
    #$type = 'text/plain';
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
250
    header("Content-Type: $type; charset=$charset");
251
    if ($last_mod>0)
252
        header('Last-Modified: ' . date('r', $last_mod));
253
    return false;
254
}
255
256
function api_error($e) {
257
    api_output(array('error' => $e));
258
}
259
260
function api_output_php($arr) {
261
    $out = serialize($arr);
262
    if (get_http_var('verbose')) $out = str_replace(';', ";\n", $out);
263
    return $out;
264
}
265
266
function api_output_rabx($arr) {
267
    $out = '';
268
    rabx_wire_wr($arr, $out);
269
    if (get_http_var('verbose')) $out = str_replace(',', ",\n", $out);
270
    return $out;
271
}
272
273
$api_xml_arr = 0;
274
function api_output_xml($v, $k=null) {
0 ignored issues
show
Unused Code introduced by
The parameter $k is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

274
function api_output_xml($v, /** @scrutinizer ignore-unused */ $k=null) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
275
    global $api_xml_arr;
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...
276
    $verbose = get_http_var('verbose') ? "\n" : '';
277
    if (is_array($v)) {
278
        if (count($v) && array_keys($v) === range(0, count($v)-1)) {
279
            $elt = 'match';
280
            $api_xml_arr++;
281
            $out = "<$elt>";
282
            $out .= join("</$elt>$verbose<$elt>", array_map('api_output_xml', $v));
283
            $out .= "</$elt>$verbose";
284
            return $out;
285
        }
286
        $out = '';
287
        foreach ($v as $k => $vv) {
288
            $out .= (is_numeric($k) || strpos($k, ' ')) ? '<match><id>' . _htmlspecialchars($k) . '</id>' : "<$k>";
289
            $out .= api_output_xml($vv, $k);
290
            $out .= (is_numeric($k) || strpos($k, ' ')) ? '</match>' : "</$k>";
291
            $out .= $verbose;
292
        }
293
        return $out;
294
    } else {
295
        return _htmlspecialchars($v);
296
    }
297
}
298
299
function api_output_js($v, $level=0) {
300
    $verbose = get_http_var('verbose') ? "\n" : '';
301
    $out = '';
302
    if (is_array($v)) {
303
        # PHP arrays are both JS arrays and objects
304
        if (count($v) && array_keys($v) === range(0, count($v)-1)) {
305
            $out = '[' . join(",$verbose" , array_map('api_output_js', $v)) . ']';
306
        } else {
307
            $out = '{' . $verbose;
308
            $b = false;
309
            foreach ($v as $k => $vv) {
310
                if ($b) $out .= ",$verbose";
311
                if ($verbose) {
312
                    $out .= str_repeat(' ', ($level+1)*2);
313
                    $out .= '"' . $k . '" : ';
314
                } else {
315
                    $out .= '"' . $k . '":';
316
                }
317
                $out .= api_output_js($vv, $level+1);
318
                $b = true;
319
            }
320
            if ($verbose) $out .= "\n" . str_repeat(' ', $level*2);
321
            $out .= '}';
322
        }
323
    } elseif (is_null($v)) {
324
        $out = "null";
325
    } elseif (is_string($v)) {
326
        $out = '"' . str_replace(
327
            array("\\",'"',"\n","\t","\r", "‶", "″", "“", "”"),
328
            array("\\\\",'\"','\n','\t','\r', '\"', '\"', '\"', '\"'), $v) . '"';
329
    } elseif (is_bool($v)) {
330
        $out = $v ? 'true' : 'false';
331
    } elseif (is_int($v) || is_float($v)) {
332
        $out = $v;
333
    }
334
335
    // we only want to convert to iso if it's an actual API call
336
    // so skip this if it's a documentation page
337
    if (!get_http_var('docs')) {
338
      // and then catch any errors in the conversion and just ignore
339
      // them and return the unconverted results
340
      $converted_out = @iconv('utf-8', 'iso-8859-1//TRANSLIT', $out);
341
      if ($converted_out !== FALSE) {
342
        $out = $converted_out;
343
      }
344
    }
345
346
    return $out;
347
}
348
349
# Call an API function
350
351
function api_call_user_func_or_error($function, $params, $error, $type) {
352
    if (function_exists($function))
353
        call_user_func_array($function, $params);
354
    elseif ($type == 'api')
355
        api_error($error);
356
    else
357
        print "<p style='color:#cc0000'>$error</p>";
358
}
359
360
# Used for testing for conditional responses
361
362
$cond_wkday_re = '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)';
363
$cond_weekday_re = '(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)';
364
$cond_month_re = '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)';
365
$cond_month_map = array(
366
    'Jan' =>  1, 'Feb' =>  2, 'Mar' =>  3, 'Apr' =>  4,
367
    'May' =>  5, 'Jun' =>  6, 'Jul' =>  7, 'Aug' =>  8,
368
    'Sep' =>  9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12
369
);
370
371
$cond_date1_re = '(\d\d) ' . $cond_month_re . ' (\d\d\d\d)';
372
$cond_date2_re = '(\d\d)-' . $cond_month_re . '-(\d\d)';
373
$cond_date3_re = $cond_month_re . ' (\d\d| \d)';
374
375
$cond_time_re = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|6[012])';
376
377
function cond_parse_http_date($date) {
378
    $H = $M = $S = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $H is dead and can be removed.
Loading history...
Unused Code introduced by
The assignment to $M is dead and can be removed.
Loading history...
379
    $Y = $m = $d = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $Y is dead and can be removed.
Loading history...
Unused Code introduced by
The assignment to $m is dead and can be removed.
Loading history...
380
381
    $ma = array();
382
    global $cond_wkday_re, $cond_weekday_re, $cond_month_re, $cond_month_map,
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...
383
    $cond_date1_re, $cond_date2_re, $cond_date3_re, $cond_time_re;
384
    if (preg_match("/^$cond_wkday_re, $cond_date1_re $cond_time_re GMT\$/", $date, $ma)) {
385
        /* RFC 1123 */
386
        $d = $ma[2];
387
        $m = $cond_month_map[$ma[3]];
388
        $Y = $ma[4];
389
        $H = $ma[5];
390
        $M = $ma[6];
391
        $S = $ma[7];
392
    } elseif (preg_match("/^$cond_weekday_re, $cond_date2_re $cond_time_re GMT\$/", $date, $ma)) {
393
        /* RFC 850 */
394
        $d = $ma[2];
395
        $m = $cond_month_map[$ma[3]];
396
        $Y = $ma[4] + ($ma[4] < 50 ? 2000 : 1900); /* XXX */
397
        $H = $ma[5];
398
        $M = $ma[6];
399
        $S = $ma[7];
400
    } elseif (preg_match("/^$cond_wkday_re $cond_date3_re $cond_time_re (\\d{4})\$/", $date, $ma)) {
401
        /* asctime(3) */
402
        $d = preg_replace('/ /', '', $ma[3]);
403
        $m = $cond_month_map[$ma[2]];
404
        $Y = $ma[7];
405
        $H = $ma[4];
406
        $M = $ma[5];
407
        $S = $ma[6];
408
    } else
409
        return null;
410
411
    return gmmktime($H, $M, $S, $m, $d, $Y);
412
}
413