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

error_handler()   F

Complexity

Conditions 18
Paths 1025

Size

Total Lines 128
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
eloc 69
c 0
b 0
f 0
nc 1025
nop 5
dl 0
loc 128
rs 2
ccs 0
cts 72
cp 0
crap 342

How to fix   Long Method    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 13 and the first side effect is on line 8.

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
/*
4
General utility functions v1.1 (well, it was).
5
6
*/
7
8
include_once INCLUDESPATH . '../../commonlib/phplib/email.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...
9
include_once INCLUDESPATH . '../../commonlib/phplib/datetime.php';
10
11
# Pass it a brief header word and some debug text and it'll be output.
12
# If TEXT is an array, call the user function, assuming it's a class.
13
function twfy_debug($header, $text="") {
14
15
    // We set ?DEBUGTAG=n in the URL.
16
    // (DEBUGTAG is set in config.php).
17
    // n is a number from (currently) 1 to 4.
18
    // This sets what amount of debug information is shown.
19
    // For level '1' we show anything that is passed to this function
20
    // with a $header in $levels[1].
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...
21
    // For level '2', anything with a $header in $levels[1] AND $levels[2].
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% 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...
22
    // Level '4' shows everything.
23
24 74
    $debug_level = get_http_var(DEBUGTAG);
1 ignored issue
show
Bug introduced by
The constant DEBUGTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
25
    #$debug_level = 1;
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...
26
27 74
    if ($debug_level != '') {
28
29
        // Set which level shows which types of debug info.
30
        $levels = array (
31
            1 => array ('THEUSER', 'TIME', 'SQLERROR', 'PAGE', 'TEMPLATE', 'SEARCH', 'ALERTS', 'MP'),
32
            2 => array ('SQL', 'EMAIL', 'WIKIPEDIA', 'hansardlist', 'debatelist', 'wranslist', 'whalllist'),
33
            3 => array ('SQLRESULT')
34
            // Higher than this: 'DATA', etc.
35
        );
36
37
        // Store which headers we are allowed to show.
38
        $allowed_headers = array();
39
40
        if ($debug_level > count($levels)) {
41
            $max_level_to_show = count($levels);
42
        } else {
43
            $max_level_to_show = $debug_level;
44
        }
45
46
        for ($n = 1; $n <= $max_level_to_show; $n++) {
47
            $allowed_headers = array_merge ($allowed_headers, $levels[$n] );
48
        }
49
50
        // If we can show this header, then, er, show it.
51
        if ( in_array($header, $allowed_headers) || $debug_level >= 4) {
52
            if (is_array($text)) $text = call_user_func($text);
53
            print "<p><span style=\"color:#039;\"><strong>$header</strong></span> $text</p>\n";
54
        }
55
    }
56 74
}
57
58
function exception_handler($e) {
59
    trigger_error($e->getMessage(), E_USER_ERROR);
60
}
61
62
function error_handler($errno, $errmsg, $filename, $linenum, $vars) {
0 ignored issues
show
Unused Code introduced by
The parameter $vars 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

62
function error_handler($errno, $errmsg, $filename, $linenum, /** @scrutinizer ignore-unused */ $vars) {

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...
63
    // Custom error-handling function.
64
    // Sends an email to BUGSLIST.
65
    global $PAGE;
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...
66
67
    # Ignore errors we've asked to ignore
68
    if (error_reporting()==0) return;
69
70
   // define an assoc array of error string
71
   // in reality the only entries we should
72
   // consider are E_WARNING, E_NOTICE, E_USER_ERROR,
73
   // E_USER_WARNING and E_USER_NOTICE
74
   # Commented out are ones that a user function cannot handle.
75
    $errortype = array (
76
        #E_ERROR            => "Error",
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...
77
        E_WARNING           => "Warning",
78
        #E_PARSE            => "Parsing Error",
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...
79
        E_NOTICE            => "Notice",
80
        #E_CORE_ERROR       => "Core Error",
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...
81
        #E_CORE_WARNING     => "Core Warning",
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...
82
        #E_COMPILE_ERROR    => "Compile Error",
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...
83
        #E_COMPILE_WARNING  => "Compile Warning",
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...
84
        E_USER_ERROR        => "User Error",
85
        E_USER_WARNING      => "User Warning",
86
        E_USER_NOTICE       => "User Notice",
87
        E_STRICT            => "Runtime Notice",
88
        # 5.3 introduced E_DEPRECATED
89
        8192                => 'Deprecated',
90
    );
91
92
    $err = '';
93
    if (isset($_SERVER['REQUEST_URI'])) {
94
        $err .= "URL:\t\thttps://" . DOMAIN . $_SERVER['REQUEST_URI'] . "\n";
1 ignored issue
show
Bug introduced by
The constant DOMAIN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
95
    } else {
96
        $err .= "URL:\t\tNone - running from command line?\n";
97
    }
98
    if (isset($_SERVER['HTTP_REFERER'])) {
99
        $err .= "Referer:\t" . $_SERVER['HTTP_REFERER'] . "\n";
100
    } else {
101
        $err .= "Referer:\tNone\n";
102
    }
103
    if (isset($_SERVER['HTTP_USER_AGENT'])) {
104
        $err .= "User-Agent:\t" . $_SERVER['HTTP_USER_AGENT'] . "\n";
105
    } else {
106
        $err .= "User-Agent:\tNone\n";
107
    }
108
    $err .= "Number:\t\t$errno\n";
109
    $err .= "Type:\t\t" . $errortype[$errno] . "\n";
110
    $err .= "Message:\t$errmsg\n";
111
    $err .= "File:\t\t$filename\n";
112
    $err .= "Line:\t\t$linenum\n";
113
    if (count($_POST)) {
114
        $err .= "_POST:";
115
        foreach ($_POST as $k => $v) {
116
            $err .= "\t\t$k => $v\n";
117
        }
118
    }
119
120
// I'm not sure this bit is actually any use!
121
122
    // set of errors for which a var trace will be saved.
123
//  $user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
124
//  if (in_array($errno, $user_errors)) {
125
//      $err .= "Variables:\t" . serialize($vars) . "\n";
126
//  }
127
128
129
    // Add the problematic line if possible.
130
    if (is_readable($filename)) {
131
        $source = file($filename);
132
        $err .= "\nSource:\n\n";
133
        // Show the line, plus prev and next, with line numbers.
134
        $err .= $linenum-2 . " " . $source[$linenum-3];
135
        $err .= $linenum-1 . " " . $source[$linenum-2];
136
        $err .= $linenum . " " . $source[$linenum-1];
137
        $err .= $linenum+1 . " " . $source[$linenum];
138
        $err .= $linenum+2 . " " . $source[$linenum+1];
139
    }
140
141
142
    // Will we need to exit after this error?
143
    $fatal_errors = array(E_ERROR, E_USER_ERROR);
144
    if (in_array($errno, $fatal_errors)) {
145
        $fatal = true;
146
    } else {
147
        $fatal = false;
148
    }
149
150
    // Finally, display errors and stuff...
151
152
    if (DEVSITE || get_http_var(DEBUGTAG)) {
2 ignored issues
show
Bug introduced by
The constant DEBUGTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant DEVSITE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
153
        // On a devsite we just display the problem.
154
        $errtxt = nl2br($err) . "\n";
155
        if (!strstr($errmsg, 'mysql_connect')) {
156
            $errtxt .= "<br><br>Backtrace:<br>" . nl2br(adodb_backtrace(false));
157
        }
158
        $message = array(
159
            'title' => "Error",
160
            'text' => $errtxt
161
        );
162
        if (is_object($PAGE)) {
163
            $PAGE->error_message($message, $fatal);
164
        } else {
165
            vardump($message);
166
        }
167
168
    } else {
169
        // On live sites we display a nice message and email the problem.
170
171
        $message = array(
172
            'title' => "Sorry, an error has occurred",
173
            'text' => "We've been notified by email and will try to fix the problem soon!"
174
        );
175
176
        if (is_object($PAGE)) {
177
            $PAGE->error_message($message, $fatal);
178
        } else {
179
            header('HTTP/1.0 500 Internal Server Error');
180
            print "<p>Oops, sorry, an error has occurred!</p>\n";
181
        }
182
        if (!($errno & E_USER_NOTICE) && strpos($errmsg, 'pg_connect')===false && strpos($errmsg, 'mysql_connect')===false) {
183
            mail(BUGSLIST, "[TWFYBUG]: $errmsg", $err, "From: Bug <" . CONTACTEMAIL . ">\n".  "X-Mailer: PHP/" . phpversion() );
2 ignored issues
show
Bug introduced by
The constant CONTACTEMAIL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant BUGSLIST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
184
        }
185
    }
186
187
    // Do we need to exit?
188
    if ($fatal) {
189
        exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
190
    }
191
}
192
193
// Replacement for var_dump()
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
194
function vardump($blah) {
195
    print "<pre>\n";
196
    var_dump($blah);
1 ignored issue
show
Security Debugging Code introduced by
var_dump($blah) looks like debug code. Are you sure you do not want to remove it?
Loading history...
197
    print "</pre>\n";
198
}
199
200
// pretty prints the backtrace, copied from http://uk.php.net/manual/en/function.debug-backtrace.php
201
function adodb_backtrace($print=true)
202
{
203
  $s = '';
204
  if (PHPVERSION() >= 4.3) {
205
206
    $MAXSTRLEN = 64;
207
208
    $traceArr = debug_backtrace();
209
    array_shift($traceArr);
210
    $tabs = sizeof($traceArr)-1;
211
    foreach ($traceArr as $arr) {
212
      for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
213
      $tabs -= 1;
214
      if (isset($arr['class'])) $s .= $arr['class'].'.';
215
      $args = array();
216
      if (isset($arr['args'])) foreach ($arr['args'] as $v) {
217
    if (is_null($v)) $args[] = 'null';
218
    elseif (is_array($v)) $args[] = 'Array['.sizeof($v).']';
219
    elseif (is_object($v)) $args[] = 'Object:'.get_class($v);
220
    elseif (is_bool($v)) $args[] = $v ? 'true' : 'false';
221
    else {
222
      $v = (string) @$v;
223
      $str = _htmlspecialchars(substr($v,0,$MAXSTRLEN));
224
      if (strlen($v) > $MAXSTRLEN) $str .= '...';
225
      $args[] = $str;
226
    }
227
      }
228
229
      $s .= $arr['function'].'('.implode(', ',$args).')';
230
      //      $s .= sprintf("</font><font color=#808080 size=-1> # line %4d,".
231
      //            " file: <a href=\"file:/%s\">%s</a></font>",
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
232
      //        $arr['line'],$arr['file'],$arr['file']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
95% 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...
233
      $s .= "\n";
234
    }
235
    if ($print) print $s;
236
  }
237
238
  return $s;
239
}
240
241
// Far from foolproof, but better than nothing.
242
function validate_email($string) {
243
    if (!preg_match('/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+'.
244
        '@'.
245
        '[-!#$%&\'*.\\+\/0-9=?A-Z^_`a-z{|}~]+\.'.
246
        '[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+$/', $string)) {
247
        return false;
248
    } else {
249
        return true;
250
    }
251
}
252
253
function validate_postcode($postcode) {
254
    // See http://www.govtalk.gov.uk/gdsc/html/noframes/PostCode-2-1-Release.htm
255
256 4
    $postcode = trim($postcode);
257
258 4
    $in  = 'ABDEFGHJLNPQRSTUWXYZ';
259 4
    $fst = 'ABCDEFGHIJKLMNOPRSTUWYZ';
260 4
    $sec = 'ABCDEFGHJKLMNOPQRSTUVWXY';
261 4
    $thd = 'ABCDEFGHJKSTUW';
262 4
    $fth = 'ABEHMNPRVWXY';
263 4
    $num = '0123456789';
264 4
    $nom = '0123456789';
265 4
    $gap = '\s\.';
266
267 4
    if (    preg_match("/^[$fst][$num][$gap]*[$nom][$in][$in]$/i", $postcode) ||
268 4
            preg_match("/^[$fst][$num][$num][$gap]*[$nom][$in][$in]$/i", $postcode) ||
269 4
            preg_match("/^[$fst][$sec][$num][$gap]*[$nom][$in][$in]$/i", $postcode) ||
270 4
            preg_match("/^[$fst][$sec][$num][$num][$gap]*[$nom][$in][$in]$/i", $postcode) ||
271 3
            preg_match("/^[$fst][$num][$thd][$gap]*[$nom][$in][$in]$/i", $postcode) ||
272 3
            preg_match("/^[$fst][$sec][$num][$fth][$gap]*[$nom][$in][$in]$/i", $postcode)
273 4
        ) {
274 2
        return true;
275
    } else {
276 2
        return false;
277
    }
278
}
279
280
// Returns the unixtime in microseconds.
281
function getmicrotime() {
282 74
    $mtime = microtime();
283 74
    $mtime = explode(" ",$mtime);
284 74
    $mtime = $mtime[1] + $mtime[0];
285
286 74
    return $mtime;
287
}
288
289
/* twfy_debug_timestamp
290
 * Output a timestamp since the page was started. */
291
$timestamp_last = $timestamp_start = getmicrotime();
292
function twfy_debug_timestamp($label = "") {
293
    global $timestamp_last, $timestamp_start;
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...
294
    $t = getmicrotime();
295
    twfy_debug("TIME", sprintf("%f msecs since start; %f msecs since last; %s",
296
            ($t - $timestamp_start)*1000.0, ($t - $timestamp_last)*1000.0, $label));
297
    $timestamp_last = $t;
298
}
299
300
function format_timestamp($timestamp, $format) {
301
    // Pass it a MYSQL TIMESTAMP (YYYYMMDDHHMMSS) and a
302
    // PHP date format string (eg, "Y-m-d H:i:s")
303
    // and it returns a nicely formatted string according to requirements.
304
305
    // Because strtotime can't handle TIMESTAMPS.
306
307
    if (preg_match("/^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/", $timestamp, $matches)) {
308
        list($string, $year, $month, $day, $hour, $min, $sec) = $matches;
309
310
        return gmdate ($format, gmmktime($hour, $min, $sec, $month, $day, $year));
311
    } else {
312
        return "";
313
    }
314
315
}
316
317
318
$format_date_months = array('', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
319
$format_date_months_short = array('', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
320
321
function format_date($date, $format) {
322 16
    global $format_date_months, $format_date_months_short;
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...
323
    // Pass it a date (YYYY-MM-DD) and a
324
    // PHP date format string (eg, "Y-m-d H:i:s")
325
    // and it returns a nicely formatted string according to requirements.
326
327 16
    if (preg_match("/^(\d\d\d\d)-(\d\d?)-(\d\d?)$/", $date, $matches)) {
328 16
        list($string, $year, $month, $day) = $matches;
329 16
        if ($year < 1902) { # gmdate fns only go back to Dec. 1901
330
            if ($format == SHORTDATEFORMAT) {
331
                return ($day+0) . ' ' . $format_date_months_short[$month+0] . " $year";
332
            } else {
333
                return ($day+0) . ' ' . $format_date_months[$month+0] . " $year";
334
            }
335
        }
336
337 16
        return gmdate ($format, gmmktime(0, 0, 0, $month, $day, $year));
338
    } else {
339
        return "";
340
    }
341
342
}
343
344
345
function format_time($time, $format) {
346
    // Pass it a time (HH:MM:SS) and a
347
    // PHP date format string (eg, "H:i")
348
    // and it returns a nicely formatted string according to requirements.
349
350
    if (preg_match("/^(\d\d):(\d\d):(\d\d)$/", $time, $matches)) {
351
        list($string, $hour, $min, $sec) = $matches;
352
353
        return gmdate ($format, gmmktime($hour, $min, $sec));
354
    } else {
355
        return "";
356
    }
357
}
358
359
360
361
function relative_time($datetime) {
362
    // Pass it a 'YYYY-MM-DD HH:MM:SS' and it will return something
363
    // like "Two hours ago", "Last week", etc.
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% 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...
364
365
    // http://maniacalrage.net/projects/relative/
366
367
    if (!preg_match("/\d\d\d\d-\d\d-\d\d \d\d\:\d\d\:\d\d/", $datetime)) {
368
        return '';
369
    }
370
371
    $in_seconds = strtotime($datetime);
372
    $now = time();
373
374
    $diff   =  $now - $in_seconds;
375
    $months =  floor($diff/2419200);
376
    $diff   -= $months * 2419200;
377
    $weeks  =  floor($diff/604800);
378
    $diff   -= $weeks*604800;
379
    $days   =  floor($diff/86400);
380
    $diff   -= $days * 86400;
381
    $hours  =  floor($diff/3600);
382
    $diff   -= $hours * 3600;
383
    $minutes = floor($diff/60);
384
    $diff   -= $minutes * 60;
385
    $seconds = $diff;
386
387
388
    if ($months > 0) {
389
        // Over a month old, just show the actual date.
390
        $date = substr($datetime, 0, 10);
391
        return format_date($date, LONGDATEFORMAT);
392
393
    } else {
394
        $relative_date = '';
395
        if ($weeks > 0) {
396
            // Weeks and days
397
            $relative_date .= ($relative_date?', ':'').$weeks.' week'.($weeks>1?'s':'');
398
            $relative_date .= $days>0?($relative_date?', ':'').$days.' day'.($days>1?'s':''):'';
399
        } elseif ($days > 0) {
400
            // days and hours
401
            $relative_date .= ($relative_date?', ':'').$days.' day'.($days>1?'s':'');
402
            $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hour'.($hours>1?'s':''):'';
403
        } elseif ($hours > 0) {
404
            // hours and minutes
405
            $relative_date .= ($relative_date?', ':'').$hours.' hour'.($hours>1?'s':'');
406
            $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' minute'.($minutes>1?'s':''):'';
407
        } elseif ($minutes > 0) {
408
            // minutes only
409
            $relative_date .= ($relative_date?', ':'').$minutes.' minute'.($minutes>1?'s':'');
410
        } else {
411
            // seconds only
412
            $relative_date .= ($relative_date?', ':'').$seconds.' second'.($seconds>1?'s':'');
413
        }
414
    }
415
416
    // Return relative date and add proper verbiage
417
    return $relative_date.' ago';
418
419
}
420
421
function parse_date($date) {
422
    return datetime_parse_local_date($date, time(), 'en', 'gb');
423
}
424
425
/* strip_tags_tospaces TEXT
426
 * Return a copy of TEXT in which certain block-level HTML tags have been
427
 * replaced by single spaces, and other HTML tags have been removed. */
428
function strip_tags_tospaces($text) {
429 8
    $text = preg_replace("#\<(p|br|div|td|tr|th|table)[^>]*\>#i", " ", $text);
430
431 8
    return strip_tags(trim($text));
432
}
433
434
function trim_characters($text, $start, $length, $url_length = 60) {
435
    // Pass it a string, a numeric start position and a numeric length.
436
    // If the start position is > 0, the string will be trimmed to start at the
437
    // nearest word boundary after (or at) that position.
438
    // If the string is then longer than $length, it will be trimmed to the nearest
439
    // word boundary below (or at) that length.
440
    // If either end is trimmed, ellipses will be added.
441
    // The modified string is then returned - its *maximum* length is $length.
442
    // HTML is always stripped (must be for trimming to prevent broken tags).
443
444 8
    $text = strip_tags_tospaces($text);
445
446
    // Split long strings up so they don't go too long.
447
    // Mainly for URLs which are displayed, but aren't links when trimmed.
448 8
    $text = preg_replace('/(\S{' . $url_length . '})/', "\$1 ", $text);
449
450
    // Otherwise the word boundary matching goes odd...
451 8
    $text = preg_replace("/[\n\r]/", " ", $text);
452
453
    // Trim start.
454 8
    if ($start > 0) {
455
        $text = substr($text, $start);
456
457
        // Word boundary.
458
        if (preg_match ("/.+?\b(.*)/", $text, $matches)) {
459
            $text = $matches[1];
460
            // Strip spare space at the start.
461
            $text = preg_replace ("/^\s/", '', $text);
462
        }
463
        $text = '...' . $text;
464
    }
465
466
    // Trim end.
467 8
    if (strlen($text) > $length) {
468
469
        // Allow space for ellipsis.
470 8
        $text = substr($text, 0, $length - 3);
471
472
        // Word boundary.
473 8
        if (preg_match ("/(.*)\s.+/", $text, $matches)) {
474 8
            $text = $matches[1];
475
            // Strip spare space at the end.
476 8
            $text = preg_replace ("/\s$/", '', $text);
477 8
        }
478
        // We don't want to use the HTML entity for an ellipsis (&#8230;), because then
479
        // it screws up when we subsequently use htmlentities() to print the returned
480
        // string!
481 8
        $text .= '...';
482 8
    }
483
484 8
    return $text;
485
}
486
487
/**
488
 * Filters user input to remove unwanted HTML tags etc
489
 */
490
function filter_user_input($text, $filter_type) {
491
    // We use this to filter any major user input, especially comments.
492
    // Gets rid of bad HTML, basically.
493
    // Uses iamcal.com's lib_filter class.
494
495
    // $filter_type is the level of filtering we want:
496
    //      'comment' allows <b> and <i> tags.
497
    //      'strict' strips all tags.
498
499 1
    global $filter;
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...
500
501 1
    $text = trim($text);
502
503
    // Replace 3 or more newlines with just two newlines.
504
    //$text = preg_replace("/(\n){3,}/", "\n\n", $text);
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
505
506 1
    if ($filter_type == 'strict') {
507
        // No tags allowed at all!
508
        $filter->allowed = array ();
509
    } else {
510
        // Comment.
511
        // Only allowing <a href>, <b>, <strong>, <i> and <em>
512 1
        $filter->allowed = array (
513 1
            'a' => array('href'),
514 1
            'strong' => array(),
515 1
            'em' => array(),
516 1
            'b' => array(),
517 1
            'i' => array()
518 1
        );
519
        // turning this on means that stray angle brackets
520
        // are not turned in to tags
521 1
        $filter->always_make_tags = 0;
522
    }
523
524 1
    $text = $filter->go($text);
525
526 1
    return $text;
527
}
528
529
function prepare_comment_for_display($text) {
530
    // Makes any URLs into HTML links.
531
    // Turns \n's into <br>
532
533
    // Encode HTML entities.
534
    // Can't do htmlentities() because it'll turn the few tags we allow into &lt;
535
    // Must go before the URL stuff.
536 3
    $text = htmlentities_notags($text);
537
538 3
    $link_length = 60;
539 3
    $text = preg_replace_callback(
540 3
        "/(?<!\"|\/)((http(s?):\/\/)|(www\.))([a-zA-Z\d_.+,;:?%~\-\/#='*$!()&[\]]+)([a-zA-Z\d_?%~\-\/#='*$!&])/",
541
        function($matches) use ($link_length) {
542 2
            if (strlen($matches[0]) > $link_length) {
543 1
                return '<a href="' . $matches[0] . '" rel="nofollow">' . substr($matches[0], 0, $link_length) . "...</a>";
544
            } else {
545 1
                return '<a href="' . $matches[0] . '" rel="nofollow">' . $matches[0] . '</a>';
546
            }
547 3
        },
548 3
        $text);
549 3
    $text = str_replace('<a href="www', '<a href="http://www', $text);
550 3
    $text = preg_replace("/([\w\.]+)(@)([\w\.\-]+)/i", "<a href=\"mailto:$0\">$0</a>", $text);
551 3
    $text = str_replace("\n", "<br>\n", $text);
552
553 3
    return $text;
554
}
555
556
function htmlentities_notags($text) {
557
    // If you want to do htmlentities() on some text that has HTML tags
558
    // in it, then you need this function.
559
560 3
    $tbl = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES, 'UTF-8');
561
562
    // You could encode extra stuff...
563
    //$tbl["“"] = "&quot;";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
564
    //$tbl["”"] = "&quot;";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
565
    //$tbl["…"] = "...";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
566
    //$tbl["—"] = "-";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
567
    //$tbl["»"] = "&raquo;";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
568
    //$tbl["«"] = "&laquo;";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
569
570
  // lib_filter will replace unmatched < and > with entities so
571
  // we abuse strtr's only replace once behaviour to not double
572
  // encode them. May not be robust.
573
  // This does mean if anyone actually wants to put &gt; or &lt;
574
  // in a comment they can't but that's a lot less likely than
575
  // < or > for less than and greater than.
576 3
  $tbl['&lt;'] = "&lt;";
577 3
  $tbl['&gt;'] = "&gt;";
578
579
    // Don't want to encode these things
580 3
    unset ($tbl["<"]);
581 3
    unset ($tbl[">"]);
582 3
    unset ($tbl["'"]);
583 3
    unset ($tbl['"']);
584
585
    # strtr "will *NOT* try to replace stuff that it has already worked on."
586 3
    $text = strtr($text, $tbl);
587
588 3
    return $text;
589
}
590
591
/*
592
 * PHP 5.4 changes the default encoding for htmlentities and htmlspecialchars
593
 * to be UTF-8, not using the php.ini character encoding until PHP 5.6. So
594
 * we have to wrap all uses of these two functions.
595
 */
596
function _htmlentities($s) {
597 8
    return htmlentities($s, ENT_COMPAT, 'UTF-8');
598
}
599
function _htmlspecialchars($s) {
600
    return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
601
}
602
603
function get_canonical_gid($gid) {
604
    $db = new ParlDB;
605
    $might_be_redirected = true;
606
    while ($might_be_redirected) {
607
        $q = $db->query("SELECT gid_to FROM gidredirect WHERE gid_from = :gid", array(':gid' => $gid));
608
        if ($q->rows() > 0) {
609
            $gid = $q->field(0, 'gid_to');
610
        } else {
611
            $might_be_redirected = false;
612
        }
613
    }
614
615
    return $gid;
616
}
617
618
619
function fix_gid_from_db($gid, $keepmajor = false) {
620
    // The gids in the database are longer than we use in the site.
621
    // Feed this a gid from the db and it will be returned truncated.
622
623
    // $gid will be like 'uk.org.publicwhip/debate/2003-02-28.475.3'.
624
625
    // You will almost always want $keepmajor to be false.
626
    // This returns '2003-02-28.475.3' which is used for URLs.
627
628
    // However, trackbacks want a bit more info, so we can tell what
629
    // kind of thing they link to. So they need $keepmajor to be true.
630
    // This returns 'debate_2003-02-28.475.3'.
631
632 4
    if ($keepmajor) {
633
        $newgid = substr($gid, strpos($gid, '/')+1 );
634
        $newgid = str_replace('/', '_', $newgid);
635
    } else {
636 4
        $newgid = substr($gid, strrpos($gid, '/')+1 );
637
    }
638
639 4
    return $newgid;
640
641
}
642
643
function gid_to_anchor($gid) {
644
    // For trimming gids to be used as #anchors in pages.
645
    // Extracted here so we keep it consistent.
646
    // The gid should already be truncated using fix_gid_from_db(), so it
647
    // will be like 2003-11-20.966.0
648
    // This function returns 966.0
649
650
    return substr( $gid, (strpos($gid, '.') + 1) );
651
}
652
653
function preg_replacement_quote($s) {
654
    // This returns $s but with every $ and \ backslash-escaped.
655
    // This is to create a string that can be safely used in a
656
    // preg_replace replacement string.  This function was suggested here:
657
    // http://www.procata.com/blog/archives/2005/11/13/two-preg_replace-escaping-gotchas/
658 1
    return preg_replace('/(\$|\\\\)(?=\d)/', '\\\\\1', $s);
659
}
660
661
function send_template_email($data, $merge, $bulk = false, $want_bounces = false) {
662
    // We should have some email templates in INCLUDESPATH/easyparliament/templates/emails/.
663
664
    // $data is like:
665
    // array (
666
    //  'template'  => 'send_confirmation',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
667
    //  'to'        => '[email protected]',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
668
    //  'subject'   => 'Your confirmation email'
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...
669
    // );
670
671
    // $merge is like:
672
    // array (
673
    //  'FIRSTNAME' => 'Phil',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
674
    //  'LATNAME'   => 'Gyford'
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...
675
    //  etc...
676
    // );
677
678
    // In $data, 'template' and 'to' are mandatory. 'template' is the
679
    // name of the file (when it has '.txt' added to it).
680
681
    // We'll get the text of the template and replace all the $merge
682
    // keys with their tokens. eg, if '{FIRSTNAME}' in the template will
683
    // be replaced with 'Phil'.
684
685
    // Additionally, the first line of a template may start with
686
    // 'Subject:'. Any text immediately following that, on the same line
687
    // will be the subject of the email (it will also have its tokens merged).
688
    // But this subject can be overridden by sending including a 'subject'
689
    // pair in $data.
690
691
    global $PAGE;
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...
692
693
    if (!isset($data['to']) || $data['to'] == '') {
694
        $PAGE->error_message ("We need an email address to send to.");
695
        return false;
696
    }
697
698
    $filename = INCLUDESPATH . "easyparliament/templates/emails/" . $data['template'] . ".txt";
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...
699
700
    if (!file_exists($filename)) {
701
        $PAGE->error_message("Sorry, we could not find the email template '" . _htmlentities($data['template']) . "'.");
702
        return false;
703
    }
704
705
    // Get the text from the template.
706
    $handle = fopen($filename, "r");
707
    $emailtext = fread($handle, filesize($filename));
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

707
    $emailtext = fread(/** @scrutinizer ignore-type */ $handle, filesize($filename));
Loading history...
708
    fclose($handle);
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

708
    fclose(/** @scrutinizer ignore-type */ $handle);
Loading history...
709
710
    // See if there's a default subject in the template.
711
    $firstline = substr($emailtext, 0, strpos($emailtext, "\n"));
712
713
    // Work out what the subject line is.
714
    if (preg_match("/Subject:/", $firstline)) {
715
        if (isset($data['subject'])) {
716
            $subject = trim($data['subject']);
717
        } else {
718
            $subject = trim( substr($firstline, 8) );
719
        }
720
721
        // Either way, remove this subject line from the template.
722
        $emailtext = substr($emailtext, strpos($emailtext, "\n"));
723
724
    } elseif (isset($data['subject'])) {
725
        $subject = $data['subject'];
726
    } else {
727
        $PAGE->error_message ("We don't have a subject line for the email, so it wasn't sent.");
728
        return false;
729
    }
730
731
732
    // Now merge all the tokens from $merge into $emailtext...
733
    $search = array();
734
    $replace = array();
735
736
    foreach ($merge as $key => $val) {
737
        $search[] = '/{'.$key.'}/';
738
        $replace[] = preg_replacement_quote($val);
739
    }
740
741
    $emailtext = preg_replace($search, $replace, $emailtext);
742
743
    // Send it!
744
    $success = send_email ($data['to'], $subject, $emailtext, $bulk, 'twfy-DO-NOT-REPLY@' . EMAILDOMAIN, $want_bounces);
1 ignored issue
show
Bug introduced by
The constant EMAILDOMAIN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
745
746
    return $success;
747
748
}
749
750
/* verp_envelope_sender RECIPIENT
751
 * Construct a VERP envelope sender for an email to RECIPIENT
752
 */
753
function twfy_verp_envelope_sender($recipient) {
754
    $envelope_sender = verp_envelope_sender($recipient, 'twfy', EMAILDOMAIN);
1 ignored issue
show
Bug introduced by
The constant EMAILDOMAIN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
755
756
    return $envelope_sender;
757
}
758
759
function send_email($to, $subject, $message, $bulk = false, $from = '', $want_bounces = false) {
760
    // Use this rather than PHP's mail() direct, so we can make alterations
761
    // easily to all the emails we send out from the site.
762
    // eg, we might want to add a .sig to everything here...
763
764
    if (!$from) $from = CONTACTEMAIL;
1 ignored issue
show
Bug introduced by
The constant CONTACTEMAIL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
765
766
    $headers =
767
     "From: TheyWorkForYou <$from>\r\n" .
768
     "Content-Type: text/plain; charset=utf-8\r\n" .
769
     "MIME-Version: 1.0\r\n" .
770
     "Content-Transfer-Encoding: 8bit\r\n" .
771
     ($bulk ? "Precedence: bulk\r\nAuto-Submitted: auto-generated\r\n" : "" ).
772
     "X-Mailer: PHP/" . phpversion();
773
    twfy_debug('EMAIL', "Sending email to $to with subject of '$subject'");
774
775
    if ($want_bounces) {
776
      $envelope_sender = twfy_verp_envelope_sender($to);
777
        $success = mail ($to, $subject, $message, $headers, '-f ' . $envelope_sender);
778
    } else {
779
        $success = mail ($to, $subject, $message, $headers);
780
    }
781
782
    return $success;
783
}
784
785
786
///////////////////////////////
787
// Cal's functions from
788
// http://www.iamcal.com/publish/article.php?id=13
789
790
// Call this with a key name to get a GET or POST variable.
791
function get_http_var($name, $default='') {
792 74
    if (array_key_exists($name, $_GET)) {
793
        return clean_var($_GET[$name]);
794
    }
795 74
    if (array_key_exists($name, $_POST)) {
796
        return clean_var($_POST[$name]);
797
    }
798 74
    return $default;
799
}
800
801
function clean_var($a) {
802 3
    return (ini_get("magic_quotes_gpc") == 1) ? recursive_strip($a) : $a;
803
}
804
805
function recursive_strip($a) {
806
    if (is_array($a)) {
807
        while (list($key, $val) = each($a)) {
0 ignored issues
show
Deprecated Code introduced by
The function each() has been deprecated: 7.2 ( Ignorable by Annotation )

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

807
        while (list($key, $val) = /** @scrutinizer ignore-deprecated */ each($a)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
808
            $a[$key] = recursive_strip($val);
809
        }
810
    } else {
811
        $a = StripSlashes($a);
812
    }
813
    return $a;
814
}
815
816
// Call this with a key name to get a COOKIE variable.
817
function get_cookie_var($name, $default='') {
818 3
    if (array_key_exists($name, $_COOKIE)) {
819 3
        return clean_var($_COOKIE[$name]);
820
    }
821 3
    return $default;
822
}
823
///////////////////////////////
824
825
// Pass it an array of key names that should not be generated as
826
// hidden form variables. It then outputs hidden form variables
827
// based on the session_vars for this page.
828
function hidden_form_vars ($omit = array()) {
829
    global $DATA, $this_page;
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...
830
831
    $session_vars = $DATA->page_metadata($this_page, "session_vars");
832
833
    foreach ($session_vars as $n => $key) {
834
        if (!in_array($key, $omit)) {
835
            print "<input type=\"hidden\" name=\"$key\" value=\"" . _htmlentities(get_http_var($key)) . "\">\n";
836
        }
837
    }
838
}
839
840
// Deprecated. Use hidden_form_vars, above, instead.
841
function hidden_vars ($omit = array()) {
842
    global $DATA;
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...
843
844
    foreach ($args as $key => $val) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $args seems to be never defined.
Loading history...
845
        if (!in_array($key, $omit)) {
846
            print "<input type=\"hidden\" name=\"$key\" value=\"" . _htmlspecialchars($val) . "\">\n";
847
        }
848
    }
849
}
850
851
function make_ranking($rank)
852
{
853
    $rank = $rank + 0;
854
855
    # 11th, 12th, 13th use "th" not "st", "nd", "rd"
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% 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...
856
    if (floor(($rank % 100) / 10) == 1)
857
        return $rank . "th";
858
    # 1st
859
    if ($rank % 10 == 1)
860
        return $rank . "st";
861
    # 2nd
862
    if ($rank % 10 == 2)
863
        return $rank . "nd";
864
    # 3rd
865
    if ($rank % 10 == 3)
866
        return $rank . "rd";
867
    # Everything else use th
868
869
    return $rank . "th";
870
}
871
872
function make_plural($word, $number)
873
{
874
    if ($number == 1)
875
        return $word;
876
    return $word . "s";
877
}
878
879
# Can't have the entities in XML so replace all theones we currently have with numerical entities
880
# This is yucky. XXX
881
function entities_to_numbers($string) {
882
    $string = str_replace(
883
        array('&Ouml;', '&acirc;', '&uacute;', '&aacute;', '&iacute;', '&ocirc;', '&eacute;'),
884
        array('&#214;', '&#226;',  '&#250;',   '&#225;',   '&#237;',   '&#244;',  '&#233;'  ),
885
        $string
886
    );
887
    return $string;
888
}
889
890
function make_member_url($name, $const = '', $house = HOUSE_TYPE_COMMONS, $pid = NULL) {
891
892
    // Case for Elizabeth II
893 10
    if ($house == HOUSE_TYPE_ROYAL)
894 10
    {
895 1
        return 'elizabeth_the_second';
896
    }
897
898 9
    $s   = array(' ', '&amp;', '&ocirc;',  '&Ouml;',  '&ouml;',   '&acirc;',  '&iacute;', '&aacute;', '&uacute;', '&eacute;', '&oacute;', '&Oacute;');
899 9
    $s2  = array(" ", "&",     "\xc3\xb4", "\xc3\96", "\xc3\xb6", "\xc3\xa5", "\xc3\xad", "\xc3\xa1", "\xc3\xba", "\xc3\xa9", "\xc3\xb3", "\xc3\x93");
900 9
    $r   = array('_', 'and',   'o',        'o',       'o',        'a',        'i',        'a',        'u',        'e',        'o',        'o');
901 9
    $name = preg_replace('#^the #', '', strtolower($name));
902
903 9
    $out = '';
904
905
    // Insert the Person ID if known.
906 9
    if ($pid !== NULL)
907 9
    {
908 9
        $out .= $pid . '/';
909 9
    }
910
911
    // Always inject the person's name
912 9
    $out .= urlencode(str_replace($s2, $r, str_replace($s, $r, $name)));
913
914
    // If there is a constituency, inject that too
915 9
    if ($const && $house == HOUSE_TYPE_COMMONS)
916 9
    {
917 3
        $out .= '/' . urlencode(str_replace($s2, $r, str_replace($s, $r, strtolower($const))));
918 3
    }
919
920 9
    return $out;
921
}
922
923
function member_full_name($house, $title, $given_name, $family_name, $lordofname) {
924 14
    $s = 'ERROR';
925 14
    if ($house == HOUSE_TYPE_COMMONS || $house == HOUSE_TYPE_NI || $house == HOUSE_TYPE_SCOTLAND) {
926 11
        $s = "$given_name $family_name";
927 11
        if ($title) {
928 7
            $s = $title . ' ' . $s;
929 7
        }
930 14
    } elseif ($house == HOUSE_TYPE_LORDS) {
931 2
        $s = '';
932 2
        if (!$family_name) $s = 'the ';
933 2
        $s .= $title;
934 2
        if ($family_name) $s .= ' ' . $family_name;
935 2
        if ($lordofname) $s .= ' of ' . $lordofname;
936 3
    } elseif ($house == HOUSE_TYPE_ROYAL) { # Queen
937 1
        $s = "$given_name $family_name";
938 1
    }
939 14
    return $s;
940
}
941
942
function prettify_office($pos, $dept) {
943
    $lookup = array(
944
        'Prime Minister, HM Treasury' => 'Prime Minister',
945
        'Secretary of State, Foreign & Commonwealth Office' => 'Foreign Secretary',
946
        'Secretary of State, Home Office' => 'Home Secretary',
947
        'Minister of State (Energy), Department of Trade and Industry'
948
            => 'Minister for energy, Department of Trade and Industry',
949
        'Minister of State (Pensions), Department for Work and Pensions'
950
            => 'Minister for pensions, Department for Work and Pensions',
951
        'Parliamentary Secretary to the Treasury, HM Treasury' => 'Chief Whip',
952
        'The Parliamentary Secretary to the Treasury' => 'Chief Whip',
953
        "Treasurer of Her Majesty's Household, HM Household" => "Deputy Chief Whip",
954
        "The Treasurer of Her Majesty's Household, HM Household" => "Deputy Chief Whip",
955
        'Comptroller, HM Household' => 'Government Whip',
956
        'Vice Chamberlain, HM Household' => 'Government Whip',
957
        "The Vice-Chamberlain of Her Majesty's Household" => 'Government Whip',
958
        'Lords Commissioner, HM Treasury' => 'Government Whip',
959
        "The Lord Commissioner of Her Majesty's Treasury" => 'Government Whip',
960
        'Assistant Whip, HM Treasury' => 'Assistant Whip',
961
        'Lords in Waiting, HM Household' => 'Government Whip',
962
        'Lords in Waiting (HM Household)' => 'Government Whip',
963
        'Baronesses in Waiting, HM Household' => 'Government Whip',
964
    );
965
    if ($pos) { # Government post, or Chairman of Select Committee
966
        $pretty = $pos;
967
        if ($dept && $dept != 'No Department') $pretty .= ", $dept";
968
        if (array_key_exists($pretty, $lookup))
969
            $pretty = $lookup[$pretty];
970
    } else { # Member of Select Committee
971
        $pretty = "Member, $dept";
972
    }
973
    return $pretty;
974
}
975
976
function major_summary($data, $echo = true) {
977
    global $hansardmajors;
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...
978
    $html = '';
979
    $db = new ParlDB;
980
    $one_date = false;
981
982
    //if no printed majors passed, default to all
983
    if (!isset($printed_majors)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $printed_majors seems to never exist and therefore isset should always be false.
Loading history...
984
        $printed_majors = array(1, 2, 4, 3, 5, 101, 7); # 8
985
    }
986
987
    // single date?
988
    if (isset($data['date'])) $one_date = true;
989
990
    // remove empty entries, so they don't produce errors
991
    foreach (array_keys($hansardmajors) as $major) {
992
        if (array_key_exists($major, $data)) {
993
            if (count($data[$major]) == 0)
994
                unset($data[$major]);
995
        }
996
    }
997
998
    //work out the date text to be displaid
999
    $daytext = array();
1000
    if (!$one_date) {
1001
        $todaystime = gmmktime(0, 0, 0, date('m'), date('d'), date('Y'));
0 ignored issues
show
Bug introduced by
date('m') of type string is incompatible with the type integer expected by parameter $month of gmmktime(). ( Ignorable by Annotation )

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

1001
        $todaystime = gmmktime(0, 0, 0, /** @scrutinizer ignore-type */ date('m'), date('d'), date('Y'));
Loading history...
Bug introduced by
date('Y') of type string is incompatible with the type integer expected by parameter $year of gmmktime(). ( Ignorable by Annotation )

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

1001
        $todaystime = gmmktime(0, 0, 0, date('m'), date('d'), /** @scrutinizer ignore-type */ date('Y'));
Loading history...
Bug introduced by
date('d') of type string is incompatible with the type integer expected by parameter $day of gmmktime(). ( Ignorable by Annotation )

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

1001
        $todaystime = gmmktime(0, 0, 0, date('m'), /** @scrutinizer ignore-type */ date('d'), date('Y'));
Loading history...
1002
        foreach ($data as $major => $array) {
1003
            if (!in_array('timestamp', $array)) $daytext[$major] = "The most recent ";
1004
            elseif ($todaystime - $array['timestamp'] == 86400) $daytext[$major] = "Yesterday&rsquo;s";
1005
            elseif ($todaystime - $array['timestamp'] <= (6 * 86400)) $daytext[$major] = gmdate('l', $array['timestamp']) . "&rsquo;s";
1006
            else $daytext[$major] = "The most recent ";
1007
        }
1008
    }
1009
1010
    //build html
1011
    foreach ($printed_majors as $p_major) {
1012
        if (!array_key_exists($p_major, $data))
1013
            continue;
1014
1015
        if ($one_date)
1016
            $date = $data['date'];
1017
        else
1018
            $date = $data[$p_major]['hdate'];
1019
        $q = $db->query('SELECT section_id, body, gid
1020
                FROM hansard, epobject
1021
                WHERE hansard.epobject_id = epobject.epobject_id '
1022
                . ($p_major == 4 ? 'AND subsection_id=0' : 'AND section_id=0') .
1023
                ' AND hdate = "' . $date . '"
1024
                AND major = ' . $p_major . '
1025
                ORDER BY hpos');
1026
        $out = '';
1027
        $LISTURL = new \MySociety\TheyWorkForYou\Url($hansardmajors[$p_major]['page_all']);
1028
        $current_sid = 0;
1029
        for ($i = 0; $i < $q->rows(); $i++) {
1030
            $gid = fix_gid_from_db($q->field($i, 'gid'));
1031
            $body = $q->field($i, 'body');
1032
            $section_id = $q->field($i, 'section_id');
1033
            //if (strstr($body, 'Chair]')) continue;
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...
1034
            if ($p_major == 4 && !$section_id) {
1035
                if ($current_sid++) {
1036
                    $out .= '</ul>';
1037
                }
1038
                $out .= '<li>' . $body . '<ul>';
1039
            } else {
1040
                $LISTURL->insert( array( 'id' => $gid ) );
1041
                $out .= '<li><a href="'.$LISTURL->generate().'">';
1042
                $out .= $body . '</a>';
1043
            }
1044
        }
1045
        if ($out) {
1046
            $html .= _major_summary_title($p_major, $data, $LISTURL, $daytext);
1047
            $html .= '<ul class="hansard-day">';
1048
            $html .= $out;
1049
            $html .= '</ul>';
1050
        }
1051
    }
1052
    $html .= '</ul>';
1053
1054
    if ($echo) {
1055
        print $html;
1056
    } else {
1057
        return $html;
1058
    }
1059
}
1060
1061
function _major_summary_title($major, $data, $LISTURL, $daytext) {
1062
    global $hansardmajors;
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...
1063
1064
    $return = '<h4>';
1065
    if (isset($daytext[$major])) {
1066
     $return .= $daytext[$major] . ' ';
1067
    }
1068
1069
    $return .= '<a href="';
1070
    if (isset($data[$major]['listurl']))
1071
        $return .= $data[$major]['listurl'];
1072
    else {
1073
        $LISTURL->reset();
1074
        $return .= $LISTURL->generate();
1075
    }
1076
    $return .= '">' . $hansardmajors[$major]['title'] . '</a>';
1077
    if (isset($daytext[$major])) $return;
1078
    $return .= '</h4>';
1079
1080
    return $return;
1081
}
1082
1083
function score_to_strongly($dmpscore) {
1084 4
    $dmpdesc = "unknown about";
1085 4
    if ($dmpscore > 0.95 && $dmpscore <= 1.0)
1086 4
        $dmpdesc = "consistently voted against";
1087 4
    elseif ($dmpscore > 0.85)
1088 1
        $dmpdesc = "almost always voted against";
1089 3
    elseif ($dmpscore > 0.6)
1090
        $dmpdesc = "generally voted against";
1091 3
    elseif ($dmpscore > 0.4)
1092 2
        $dmpdesc = "voted a mixture of for and against";
1093 1
    elseif ($dmpscore > 0.15)
1094
        $dmpdesc = "generally voted for";
1095 1
    elseif ($dmpscore > 0.05)
1096
        $dmpdesc = "almost always voted for";
1097 1
    elseif ($dmpscore >= 0.0)
1098
        $dmpdesc = "consistently voted for";
1099 4
    return $dmpdesc;
1100
}
1101
1102
function valid_url($url) {
1103
    $return = false;
1104
    if (preg_match("/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?/i", $url)) {
1105
        $return = true;
1106
    }
1107
    return $return;
1108
}
1109
1110
function redirect($url) {
1111
    if (defined('TESTING')) {
1112
        print "Location: $url";
1113
    } else {
1114
        header("Location: $url", true, 301);
1115
    }
1116
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1117
}
1118
1119
function cache_version($file) {
1120
    static $version_hash = array();
1121
    $path = BASEDIR . "/$file";
1122
    if (is_file($path) && (!isset($version_hash[$file]) || DEVSITE)) {
1 ignored issue
show
Bug introduced by
The constant DEVSITE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1123
        $version_hash[$file] = stat($path)[9];
1124
        $file .= '?' . $version_hash[$file];
1125
    }
1126
    return WEBPATH . $file;
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...
1127
}
1128