Passed
Push — master ( dbb74a...a3084c )
by David
13:21 queued 01:16
created

check_validated_email()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2021 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
// Utility functions for BOINC web pages
20
// Stuff that's not web-specific (e.g. that's used in non-web scripts)
21
// should go in util_basic.inc
22
23
error_reporting(E_ALL);
24
ini_set('display_errors', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $value of ini_set(). ( Ignorable by Annotation )

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

24
ini_set('display_errors', /** @scrutinizer ignore-type */ true);
Loading history...
25
ini_set('display_startup_errors', true);
26
27
require_once("../inc/util_basic.inc");
28
require_once("../project/project.inc");
29
require_once("../inc/countries.inc");
30
require_once("../inc/db.inc");
31
require_once("../inc/boinc_db.inc");
32
require_once("../inc/translation.inc");
33
require_once("../inc/profile.inc");
34
require_once("../inc/bootstrap.inc");
35
36
// parse some stuff from config.xml (do it here for efficiency)
37
//
38
$config = get_config();
39
global $master_url;
40
$master_url = parse_config($config , "<master_url>");
41
$recaptcha_public_key = parse_config($config, "<recaptcha_public_key>");
42
$recaptcha_private_key = parse_config($config, "<recaptcha_private_key>");
43
44
// the following default to on
45
//
46
$x = parse_config($config, "<user_country>");
47
define('USER_COUNTRY', ($x===null)?1:(int)$x);
48
49
$x = parse_config($config, "<user_url>");
50
define('USER_URL', ($x===null)?1:(int)$x);
51
52
// don't allow /... at the end of URL
53
//
54
if (array_key_exists("PATH_INFO", $_SERVER)) {
55
    die("bad URL");
56
}
57
58
// define TIMEZONE in project.inc
59
//
60
if (defined('TIMEZONE')) {
61
    date_default_timezone_set(TIMEZONE);
62
} else {
63
    date_default_timezone_set('UTC');
64
}
65
66
if (!defined('DISABLE_PROFILES')) {
67
    define('DISABLE_PROFILES', false);
68
}
69
if (!defined('DISABLE_FORUMS')) {
70
    define('DISABLE_FORUMS', false);
71
}
72
if (!defined('DISABLE_TEAMS')) {
73
    define('DISABLE_TEAMS', false);
74
}
75
if (!defined('DISABLE_BADGES')) {
76
    define('DISABLE_BADGES', false);
77
}
78
if (!defined('BADGE_HEIGHT_SMALL')) {
79
    define('BADGE_HEIGHT_SMALL', 20);
80
}
81
if (!defined('BADGE_HEIGHT_MEDIUM')) {
82
    define('BADGE_HEIGHT_MEDIUM', 24);
83
}
84
if (!defined('BADGE_HEIGHT_LARGE')) {
85
    define('BADGE_HEIGHT_LARGE', 56);
86
}
87
if (!defined('LDAP_HOST')) {
88
    define('LDAP_HOST', null);
89
}
90
if (!defined('POSTAL_CODE')) {
91
    define('POSTAL_CODE', false);
92
}
93
if (!defined('NO_COMPUTING')) {
94
    define('NO_COMPUTING', false);
95
}
96
if (!defined('NO_HOSTS')) {
97
    define('NO_HOSTS', false);
98
}
99
if (!defined('NO_STATS')) {
100
    define('NO_STATS', false);
101
}
102
if (!defined('NO_GLOBAL_PREFS')) {
103
    define('NO_GLOBAL_PREFS', false);
104
}
105
if (!defined('USER_HOME')) {
106
    define('USER_HOME', 'home.php');
107
}
108
if (!defined('POST_MAX_LINKS')) {
109
    define('POST_MAX_LINKS', 0);
110
}
111
if (!defined('DARK_MODE')) {
112
    define('DARK_MODE', false);
113
}
114
// require validated email to post in forums, send PMs, or make a profile
115
if (!defined('VALIDATE_EMAIL_TO_POST')) {
116
    define('VALIDATE_EMAIL_TO_POST', false);
117
}
118
119
// sleep this long on any login failure
120
// (slow the rate of hacker attacks)
121
//
122
define('LOGIN_FAIL_SLEEP_SEC', 5);
123
124
$caching = false;
125
    // if set, we're writing to a file rather than to client
126
$did_page_head = false;
127
128
define('KILO', 1024);
129
define('MEGA', 1024*KILO);
130
define('GIGA', 1024*MEGA);
131
132
// return true if this page is HTTPS
133
//
134
function is_https() {
135
    return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'];
136
}
137
138
function secure_url_base() {
139
    if (defined('SECURE_URL_BASE')) return SECURE_URL_BASE;
140
    return URL_BASE;
141
}
142
143
function url_base() {
144
    return is_https()?secure_url_base():URL_BASE;
145
}
146
147
function send_cookie($name, $value, $permanent, $ops=false) {
148
    global $master_url;
149
150
    // the following allows independent login for projects on the same server
151
    //
152
    $url = parse_url($master_url);
153
    $path = $url['path'];
154
    if ($ops) {
155
        $path = substr($path, 0, -1);
156
        $path .= "_ops/";
157
    }
158
    $expire = $permanent?time()+3600*24*365:0;
159
    setcookie($name, $value, $expire, $path);
160
}
161
162
function clear_cookie($name, $ops=false) {
163
    global $master_url;
164
    $url = parse_url($master_url);
165
    $path = $url['path'];
166
    if ($ops) {
167
        $path = substr($path, 0, -1);
168
        $path .= "_ops/";
169
    }
170
    setcookie($name, '', time()-3600, $path);
171
}
172
173
$g_logged_in_user = null;
174
$got_logged_in_user = false;
175
176
function get_logged_in_user($must_be_logged_in=true) {
177
    global $g_logged_in_user, $got_logged_in_user;
178
    if ($got_logged_in_user) return $g_logged_in_user;
179
180
    if (web_stopped()) return null;
181
182
    $authenticator = null;
183
    if (isset($_COOKIE['auth'])) $authenticator = $_COOKIE['auth'];
184
185
    $authenticator = BoincDb::escape_string($authenticator);
186
    if ($authenticator) {
187
        $g_logged_in_user = BoincUser::lookup("authenticator='$authenticator'");
188
    }
189
    if ($must_be_logged_in && !$g_logged_in_user) {
190
        $next_url = '';
191
        if (array_key_exists('REQUEST_URI', $_SERVER)) {
192
            $next_url = $_SERVER['REQUEST_URI'];
193
            $n = strrpos($next_url, "/");
194
            if ($n) {
195
                $next_url = substr($next_url, $n+1);
196
            }
197
        }
198
        $next_url = urlencode($next_url);
199
        Header("Location: ".url_base()."login_form.php?next_url=$next_url");
0 ignored issues
show
Coding Style introduced by
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
200
        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...
201
    }
202
    $got_logged_in_user = true;
203
    return $g_logged_in_user;
204
}
205
206
function show_login_info($prefix="") {
207
    $user = get_logged_in_user(false);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $user is correct as get_logged_in_user(false) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
208
    if ($user) {
209
        $url_tokens = url_tokens($user->authenticator);
210
        echo "<nobr>$user->name &middot; <a href=".$prefix."logout.php?$url_tokens>".tra("log out")."</a></nobr>";
211
    } else {
212
        echo "<a href=".$prefix."login_form.php>".tra("log in")."</a>";
213
    }
214
}
215
216
$cache_control_extra="";
217
$is_login_page = false;
218
219
// Call this to start pages.
220
// Outputs some HTML boilerplate,
221
// then calls project_banner() (in html/project/project.inc)
222
// to output whatever you want at the top of your web pages.
223
//
224
// Page_head() is overridable so that projects that want to integrate BOINC
225
// with an existing web framework can more easily do so.
226
// To do so, define page_head() in the project include file.
227
//
228
if (!function_exists("page_head")){
229
function page_head(
230
    $title,
231
        // page title. Put in <title>, used as title for browser tab.
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
232
    $body_attrs=null,
233
        // <body XXXX>
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
234
        // e.g. Javascript to put focus in an input field
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
235
        // (onload="document.form.foo.focus()")
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
236
        // or to jump to a particular post (onload="jumpToUnread();")
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
237
    $is_main = false,
238
        // if set, include schedulers.txt.
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
239
        // also pass to project_banner() in case you want a different
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
240
        // header for your main page.
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
241
    $url_prefix="",
242
        // prepend this to links.
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
243
        // Use for web pages not in the top directory
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
244
    $head_extra=null
245
        // extra stuff to put in <head>. E.g.:
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
246
        // reCAPTCHA code (create_profile.php)
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
247
        // bbcode javascript (forums)
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
248
) {
249
    global $caching, $cache_control_extra, $did_page_head;
250
    global $is_login_page, $fixed_navbar;
251
252
    if ($did_page_head) {
253
        return;
254
    }
255
    
256
    $did_page_head = true;
257
    $url_base = url_base();
258
259
    $rssname = "RSS 2.0";
260
    $rsslink = $url_base."rss_main.php";
261
262
    if (!$caching) {
263
        header("Content-type: text/html; charset=utf-8");
264
        header("Expires: Mon, 26 Jul 1997 05:00:00 UTC");
265
            // Date in the past
266
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " UTC");
267
            // always modified
268
        header("Cache-Control: $cache_control_extra no-cache, must-revalidate, post-check=0, pre-check=0");
269
            // for HTTP/1.1
270
        header("Pragma: no-cache");
271
            // for HTTP/1.0
272
    }
273
274
    echo '<!DOCTYPE html>
275
        <html lang="en">
276
        <head>
277
    ';
278
    if (defined('GLOBAL_HEAD_EXTRA')) {
279
        echo GLOBAL_HEAD_EXTRA;
280
    }
281
    echo '
282
        <meta name="viewport" content="width=device-width, initial-scale=1">
283
    ';
284
    if ($head_extra) {
285
        echo "\n$head_extra\n";
286
    }
287
    if ($is_main && (!defined('NO_COMPUTING')||!NO_COMPUTING)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after logical operator; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before logical operator; 0 found
Loading history...
288
        readfile("schedulers.txt");
289
    }
290
291
    $t = $title?$title:PROJECT;
292
    echo "<title>$t</title>\n";
293
    echo '
294
        <meta charset="utf-8">
295
    ';
296
    if (DARK_MODE) {
297
        echo <<<EOT
0 ignored issues
show
Coding Style introduced by
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
298
<script>
299
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
300
      console.log("foobar");
301
    document.documentElement.style.display = 'none';
302
    document.head.insertAdjacentHTML(
303
        'beforeend',
304
        '<link rel="stylesheet" href="sample_bootstrap.min.css" onload="document.documentElement.style.display = \'\'"><link rel="stylesheet" href="custom.css">'
305
    );
306
  }
307
</script>
308
<link rel="stylesheet" href="bootstrap_darkly.min.css" media="(prefers-color-scheme: dark)">
309
<link rel="stylesheet" href="custom_dark.css" media="(prefers-color-scheme: dark)">
310
<link rel="stylesheet" href="sample_bootstrap.min.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">
311
<link rel="stylesheet" href="custom.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">
312
EOT;
313
    } else {
314
        echo '
315
            <link type="text/css" rel="stylesheet" href="'.secure_url_base().'/bootstrap.min.css" media="all">
316
        ';
317
    }
318
    if (defined('STYLESHEET')) {
319
        $stylesheet = $url_base.STYLESHEET;
320
        echo "
321
            <link rel=stylesheet type=\"text/css\" href=\"$stylesheet\">
322
        ";
323
    }
324
    if (defined('STYLESHEET2')) {
325
        $stylesheet2 = $url_base.STYLESHEET2;
326
        echo "
327
            <link rel=stylesheet type=\"text/css\" href=\"$stylesheet2\">
328
        ";
329
    }
330
331
    if (defined("SHORTCUT_ICON")) {
332
        echo '<link rel="icon" type="image/x-icon" href="'.SHORTCUT_ICON.'"/>
333
';
334
    }
335
336
    echo "
337
        <link rel=alternate type=\"application/rss+xml\" title=\"$rssname\" href=\"$rsslink\">
338
        </head>
339
    ";
340
    if ($fixed_navbar) {
341
        $body_attrs .= ' style="padding-top:70px"';
342
    }
343
    echo "<body $body_attrs>";
344
    display_cvs_versions();
345
    echo '<div class="container-fluid">
346
    ';
347
348
    switch($title) {    //kludge
349
    case tra("Log in"):
350
    case tra("Create an account"):
351
    case tra("Server status page"):
352
        $is_login_page = true;
353
        break;
354
    default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
Comment required for empty DEFAULT case
Loading history...
355
        break;
356
    }
357
    project_banner($title, $url_prefix, $is_main);
358
}
359
}
360
361
// See the comments for page_head()
362
//
363
if (!function_exists("page_tail")){
364
function page_tail(
365
    $show_date=false,
366
        // true for pages that are generated periodically rather than on the fly
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
367
    $url_prefix="",
368
        // use for pages not at top level
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
369
    $is_main=false
370
        // passed to project_footer;
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 4 spaces but found 8
Loading history...
371
) {
372
    echo "<br>\n";
373
    project_footer($is_main, $show_date, $url_prefix);
374
    echo '
375
        <script src="'.secure_url_base().'/jquery.min.js"></script>
376
        <script src="'.secure_url_base().'/bootstrap.min.js"></script>
377
        </div>
378
        </body>
379
        </html>
380
    ';
381
}
382
}
383
384
function display_cvs_versions(){
385
    global $cvs_version_tracker;
386
    echo "\n<!-- SVN VERSIONS -->\n";
387
    for ($i=0;$i<sizeof($cvs_version_tracker);$i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Coding Style introduced by
Expected 1 space after first semicolon of FOR loop; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after second semicolon of FOR loop; 0 found
Loading history...
Coding Style Performance introduced by
The use of sizeof() inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead
Loading history...
388
        echo "<!-- ".$cvs_version_tracker[$i]." -->\n";
389
    }
390
}
391
392
function db_error_page() {
393
    page_head("Database error");
394
    echo tra("A database error occurred while handling your request; please try again later.");
395
    page_tail();
396
}
397
398
function error_page($msg) {
399
    global $generating_xml;
400
    if ($generating_xml) {
401
        xml_error(-1, $msg);
402
    }
403
    page_head(tra("Unable to handle request"));
404
    echo $msg;
405
    page_tail();
406
    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...
407
}
408
409
// takes argument in second and returns a human formatted time string
410
// in the form D days + h Hours + m Min + s sec.
411
412
function time_diff($x, $res=3) {
413
    $days    = (int)($x/86400);
414
    $hours   = (int)(($x-$days*86400)/3600);
415
    $minutes = (int)(($x-$days*86400-$hours*3600)/60);
416
    $seconds = (int)($x % 60);
417
418
    $datestring = "";
419
    if ($days) {
420
        $datestring .= "$days ".tra("days")." ";
421
    }
422
    if ($res>0 && ($hours || strlen($datestring))) {
423
        $datestring .= "$hours ".tra("hours")." ";
424
    }
425
    if ($res>1 && ($minutes || strlen($datestring))) {
426
        $datestring .= "$minutes ".tra("min")." ";
427
    }
428
    if ($res>2 && ($seconds)) {
429
        $datestring .= "$seconds ".tra("sec")." ";
430
    }
431
432
    return $datestring;
433
}
434
435
436
function date_str($x) {
437
    if ($x == 0) return "---";
438
    return gmdate('j M Y', $x);
439
}
440
441
function time_str($x) {
442
    if ($x == 0) return "---";
443
    return gmdate('j M Y, G:i:s', $x) . " UTC";
444
}
445
446
function local_time_str($x) {
447
    if ($x == 0) return "---";
448
    return date('j M Y, H:i T', $x);
449
}
450
451
function pretty_time_str($x) {
452
    return time_str($x);
453
}
454
455
function start_table_str($class="", $style="") {
456
    $s = $style?'style="'.$style.'"':'';
457
    return '<div class="table">
458
      <table '.$s.' width="100%" class="table table-condensed '.$class.'" >
459
    ';
460
}
461
462
function start_table($class="", $style="") {
463
    echo start_table_str($class, $style);
464
}
465
466
function end_table_str() {
467
    return '</table>
468
        </div>
469
    ';
470
}
471
472
function end_table() {
473
    echo end_table_str();
474
}
475
476
// Table header row with unlimited number of columns
477
478
function table_header() {
479
    echo "<tr>\n";
480
    $c = 'class="bg-primary"';
481
    for ($i = 0; $i < func_num_args(); $i++) {
482
        if (is_array(func_get_arg($i))) {
483
            $col = func_get_arg($i);
484
            echo "<th $c ".$col[1].">".$col[0]."</th>\n";
485
        } else {
486
            echo "<th $c>".func_get_arg($i)."</th>\n";
487
        }
488
    }
489
    echo "</tr>\n";
490
}
491
492
// Table row with unlimited number of columns
493
494
function table_row() {
495
    echo "<tr>\n";
496
    for ($i = 0; $i < func_num_args(); $i++) {
497
        if (is_array(func_get_arg($i))) {
498
            $col = func_get_arg($i);
499
            echo "<td ".$col[1].">".$col[0]."</td>\n";
500
        } else {
501
            echo "<td>".func_get_arg($i)."</td>\n";
502
        }
503
    }
504
    echo "</tr>\n";
505
}
506
507
function row1($x, $ncols=2, $class="heading") {
508
    if ($class == "heading") {
509
        echo "<tr><th class=\"bg-primary\" colspan=\"$ncols\">$x</th></tr>\n";
510
    } else {
511
        echo "<tr><td class=\"$class\" colspan=\"$ncols\">$x</td></tr>\n";
512
    }
513
}
514
515
define('NAME_ATTRS', 'class="text-right " style="padding-right:12px"');
516
define('VALUE_ATTRS', 'style="padding-left:12px"');
517
define('VALUE_ATTRS_ERR', 'class="danger" style="padding-left:12px"');
518
519
function row2($x, $y, $show_error=false, $lwidth='40%') {
520
    if ($x==="") $x="<br>";
521
    if ($y==="") $y="<br>";
522
    $attrs = $show_error?VALUE_ATTRS_ERR:VALUE_ATTRS;
523
    echo "<tr>
524
        <td width=\"$lwidth\" ".NAME_ATTRS.">$x</td>
525
        <td $attrs >$y</td>
526
        </tr>
527
    ";
528
}
529
530
function row2_init($x, $y, $lwidth='40%') {
531
    echo '<tr>
532
        <td class="text-right " width="'.$lwidth.'"  style="padding-right: 20px;">'.$x.'</td>
533
        <td '.VALUE_ATTRS.'>'.$y.'
534
    ';
535
}
536
537
function row2_plain($x, $y) {
538
    echo "<tr><td>$x</td><td>$y</td></tr>\n";
539
}
540
541
function rowify($string) {
542
    echo "<tr><td>$string</td></tr>";
543
}
544
545
function row_array($x) {
546
    echo "<tr>\n";
547
    foreach ($x as $h) {
548
        echo "<td>$h</td>\n";
549
    }
550
    echo "</tr>\n";
551
}
552
553
define ('ALIGN_RIGHT', 'style="text-align:right;"');
554
555
function row_heading_array($x, $attrs=null, $class='bg-primary') {
556
    echo "<tr>";
557
    $i = 0;
558
    foreach ($x as $h) {
559
        $a = $attrs?$attrs[$i]:"";
560
        echo "<th $a class=\"$class\">$h</th>";
561
        $i++;
562
    }
563
    echo "</tr>\n";
564
}
565
566
function row_heading($x, $class='bg-primary') {
567
    echo sprintf('<tr><th class="%s" colspan=99>%s</th></tr>
568
        ', $class, $x
569
    );
570
}
571
572
function url_tokens($auth) {
573
    $now = time();
574
    $ttok = md5((string)$now.$auth);
575
    return "&amp;tnow=$now&amp;ttok=$ttok";
576
}
577
578
function form_tokens($auth) {
579
    $now = time();
580
    $ttok = md5((string)$now.$auth);
581
    return "<input type=\"hidden\" name=\"tnow\" value=\"$now\">
582
        <input type=\"hidden\" name=\"ttok\" value=\"$ttok\">
583
    ";
584
}
585
586
function valid_tokens($auth) {
587
    $tnow = get_str('tnow', true);
588
    $ttok = get_str('ttok', true);
589
    if (!$tnow) {
590
      if (isset($_POST['tnow'])) {
591
          $tnow = $_POST['tnow'];
592
      }
593
    }
594
    if (!$ttok) {
595
      if (isset($_POST['ttok'])) {
596
          $ttok = $_POST['ttok'];
597
      }
598
    }
599
    if (!$tnow) return false;
600
    if (!$ttok) return false;
601
    $t = md5((string)$tnow.$auth);
602
    if ($t != $ttok) return false;
603
    if (time() > $tnow + 86400) return false;
604
    return true;
605
}
606
607
function check_tokens($auth) {
608
    if (valid_tokens($auth)) return;
609
    error_page(
610
        tra("Link has timed out. Please click Back, refresh the page, and try again.")
611
    );
612
}
613
614
// Generates a legal filename from a parameter string.
615
616
function get_legal_filename($name) {
617
    return strtr($name, array(','=>'', ' '=>'_'));
618
}
619
620
// Returns a string containing as many words
621
// (being collections of characters separated by the character $delimiter)
622
// as possible such that the total string length is <= $chars characters long.
623
// If $ellipsis is true, then an ellipsis is added to any sentence which
624
// is cut short.
625
626
function sub_sentence($sentence, $delimiter, $max_chars, $ellipsis=false) {
627
    $words = explode($delimiter, $sentence);
628
    $total_chars = 0;
629
    $trunc = false;
630
    $result = "";
631
632
    foreach ($words as $word) {
633
        if (strlen($result) + strlen($word) > $max_chars) {
634
            $trunc = true;
635
            break;
636
        }
637
        if ($result) {
638
            $result .= " $word";
639
        } else {
640
            $result = $word;
641
        }
642
    }
643
644
    if ($ellipsis && $trunc) {
645
        $result .= "...";
646
    }
647
648
    return $result;
649
}
650
651
// use this for user RAC and result credit
652
//
653
function format_credit($x) {
654
    return number_format($x, 2);
655
}
656
657
// use this when credit is likely to be large, e.g. team RAC
658
//
659
function format_credit_large($x) {
660
    return number_format($x, 0);
661
}
662
663
function host_link($hostid) {
664
    if ($hostid) {
665
        return "<a href=\"show_host_detail.php?hostid=$hostid\">$hostid</a>";
666
    } else {
667
        return "---";
668
    }
669
}
670
671
function open_output_buffer() {
672
    ob_start();
673
    ob_implicit_flush(0);
674
}
675
676
function close_output_buffer($filename) {
677
    $fh = fopen($filename, "w");
678
    $page = ob_get_contents();
679
    ob_end_clean();
680
    fwrite($fh, $page);
681
    fclose($fh);
682
}
683
684
function bbcode_info() {
685
    return "<br><a href=bbcode.php target=new><small>".tra("Use BBCode tags to format your text")."</small></a>\n";
686
}
687
688
// strip slashes if magic quotes in effect
689
function undo_magic_quotes($x) {
690
    if (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) {
691
        return stripslashes($x);
692
    }
693
    return $x;
694
}
695
696
// check for bogus GET args
697
//
698
function check_get_args($args) {
699
    foreach ($_GET as $key => $val) {
700
        if (!in_array($key, $args)) {
701
            Header("Location: extra_arg_$key.html");
0 ignored issues
show
Coding Style introduced by
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
702
            die;
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...
703
        }
704
    }
705
}
706
707
// returns null if the arg is optional and missing
708
//
709
function get_int($name, $optional=false) {
710
    $x=null;
711
    if (isset($_GET[$name])) $x = $_GET[$name];
712
    if (!is_numeric($x)) {
713
        if ($optional) {
714
            if ($x) {
715
                Header("Location: non_num_arg.html");
0 ignored issues
show
Coding Style introduced by
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
716
                die;
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...
717
            }
718
            return null;
719
        } else {
720
            Header("Location: missing_arg_$name.html");
0 ignored issues
show
Coding Style introduced by
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
721
            die;
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...
722
        }
723
    }
724
    return (int)$x;
725
}
726
727
// returns null if the arg is optional and missing
728
//
729
function post_num($name, $optional=false) {
730
    $x = null;
731
    if (isset($_POST[$name])) $x = $_POST[$name];
732
    if (!is_numeric($x)) {
733
        if ($optional) {
734
            return null;
735
        } else {
736
            error_page("missing or bad parameter: $name; supplied: ".htmlspecialchars($x));
737
        }
738
    }
739
    return (double)$x;
740
}
741
742
// returns null if the arg is optional and missing
743
//
744
function post_int($name, $optional=false) {
745
    $x = post_num($name, $optional);
746
    if (is_null($x)) return null;
747
    $y = (int)$x;
748
    if ($x != $y) {
749
        error_page("param $name must be an integer");
750
    }
751
    return $y;
752
}
753
754
function get_array($name) {
755
    if (isset($_GET[$name])) {
756
        return $_GET[$name];
757
    } else {
758
        return array();
759
    }
760
}
761
762
function get_str($name, $optional=false) {
763
    if (isset($_GET[$name])) {
764
        $x = $_GET[$name];
765
    } else {
766
        if (!$optional) {
767
            error_page("missing or bad parameter: $name");
768
        }
769
        $x = null;
770
    }
771
    return undo_magic_quotes($x);
772
}
773
774
function post_str($name, $optional=false) {
775
    if (isset($_POST[$name])) {
776
        $x = $_POST[$name];
777
    } else {
778
        if (!$optional) {
779
            error_page("missing or bad parameter: $name");
780
        }
781
        $x = null;
782
    }
783
    return undo_magic_quotes($x);
784
}
785
786
function post_arr($name, $optional=false) {
787
    if (isset($_POST[$name]) && is_array($_POST[$name])) {
788
        $x = $_POST[$name];
789
    } else {
790
        if (!$optional) {
791
            error_page("missing or bad parameter: $name");
792
        }
793
        $x = null;
794
    }
795
    return $x;
796
}
797
798
function is_ascii($str) {
799
    // the mb_* functions are not included by default
800
    // return (mb_detect_encoding($passwd) -= 'ASCII');
801
802
    for ($i=0; $i<strlen($str); $i++) {
0 ignored issues
show
Coding Style Performance introduced by
The use of strlen() inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead
Loading history...
803
        $c = ord(substr($str, $i));
804
        if ($c < 32 || $c > 127) return false;
805
    }
806
    return true;
807
}
808
809
// This function replaces some often made mistakes while entering numbers
810
// and gives back an error if there are false characters
811
// It will also be checked if the value is within certain borders
812
// @param string &$value reference to the value that should be verified
813
// @param double $low the lowest number of value if verified
814
// @param double $high the highest number of value if verified
815
// @return bool true if $value is numeric and within the defined borders,
816
//   false if $value is not numeric, no changes were made in this case
817
//
818
function verify_numeric(&$value, $low, $high = false) {
819
    $number = trim($value);
820
    $number = str_replace('o', '0', $number);
821
    $number = str_replace('O', '0', $number);
822
    $number = str_replace('x', '', $number); //if someone enters '0x100'
823
    $number = str_replace(',', '.', $number); // replace the german decimal separator
824
    // if no value was entered and this is ok
825
    //
826
    if ($number=='' && !$low) return true;
827
828
    // the supplied value contains alphabetic characters
829
    //
830
    if (!is_numeric($number)) return false;
831
832
    if ($number < $low) return false;
833
834
    if ($high) {
835
        if ($number > $high) return false;
836
    }
837
    $value = (double)$number;
838
    return true;
839
}
840
841
// Generate a "select" element from an array of values
842
//
843
function select_from_array($name, $array, $selection=null, $width=240) {
844
    $out = '<select style="color:#000;"class="form-control input-sm" style="width:'.$width.'px" name="'.$name.'">"';
845
846
    foreach ($array as $key => $value) {
847
        if ($value) {
848
            $out .= "<option ";
849
            if ($key == $selection) {
850
                $out .= "selected ";
851
            }
852
            $out .= "value=\"".$key."\">".$value."</option>\n";
853
        }
854
    }
855
    $out .= "</select>\n";
856
    return $out;
857
}
858
859
// Convert to entities, while preserving already-encoded entities.
860
// Do NOT use if $str contains valid HTML tags.
861
//
862
function boinc_htmlentities($str) {
863
    $str = html_entity_decode($str, ENT_COMPAT, "UTF-8");
864
    $str = htmlentities($str, ENT_COMPAT, "UTF-8");
865
    return $str;
866
}
867
868
function strip_bbcode($string){
869
    return preg_replace("/((\[.+\])+?)(.+?)((\[\/.+\])+?)/","",$string);
870
}
871
872
function current_url() {
873
    $url = "http";
874
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") {
875
        $url .= "s";
876
    }
877
    $url .= "://";
878
    $url .= $_SERVER['SERVER_NAME'];
879
    $url .= ":".$_SERVER['SERVER_PORT'];
880
    if (isset($_SERVER['REQUEST_URI'])) {
881
        $url .= $_SERVER['REQUEST_URI'];
882
    } else {
883
        if ($_SERVER['QUERY_STRING']) {
884
            $url .= "?".$_SERVER['QUERY_STRING'];
885
        }
886
    }
887
    return $url;
888
}
889
890
// Show a single link formatted to look like a button.
891
// @param url The destination URL of the button
892
// @param text The text to display on the button
893
// @param desc The title of the destination - typically used as a popup
894
// @param class The optional CSS class of the button. Defaults to a standard button
895
//
896
897
function button_text($url, $text, $desc=null, $class="btn-success btn-sm") {
898
    if (!$desc) {
899
        $desc = $text;
900
    }
901
    return sprintf(' <a href="%s" title="%s" class="btn %s">%s</a>',
902
        $url, $desc, $class, $text
903
    );
904
}
905
906
function show_button($url, $text, $desc=null, $class="btn-success btn-sm") {
907
    echo button_text($url, $text, $desc=null, $class);
908
}
909
910
// for places with a bunch of buttons, like forum posts
911
//
912
function show_button_small($url, $text, $desc=null) {
913
    echo button_text($url, $text, $desc, "btn-primary btn-xs");
914
}
915
916
// used for showing icons
917
//
918
function show_image($src, $title, $alt, $height=null) {
919
    $h = "";
920
    if ($height) {
921
        $h = "height=\"$height\"";
922
    }
923
    echo "<img class=\"icon\" border=\"0\" title=\"$title\" alt=\"$alt\" src=\"$src\" $h>";
924
}
925
926
function show_project_down() {
927
    global $did_page_head;
928
    if (!$did_page_head) {
929
        page_head(tra("Project down for maintenance"));
930
    }
931
    echo tra(
932
        "%1 is temporarily shut down for maintenance.  Please try again later.",
933
        PROJECT
934
    );
935
    page_tail();
936
    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...
937
}
938
939
function check_web_stopped() {
940
    global $generating_xml;
941
    if (web_stopped()) {
942
        if ($generating_xml) {
943
            xml_error(-183);
944
        } else {
945
            show_project_down();
946
        }
947
    }
948
}
949
950
// Connects to database server and selects database as noted in config.xml
951
// If only read-only access is necessary,
952
// tries instead to connect to <replica_db_host> if tag exists.
953
// DEPRECATED - use boinc_db.inc
954
//
955
function db_init($try_replica=false) {
956
    check_web_stopped();
957
    $retval = db_init_aux($try_replica);
958
    if ($retval == 1) {
959
        echo tra("Unable to connect to database - please try again later");
960
        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...
961
    }
962
    if ($retval == 2) {
963
        echo tra("Unable to select database - please try again later");
964
        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...
965
    }
966
    return 0;
967
}
968
969
// return a structure indicating whether project has non-deprecated
970
// apps versions for various resource types,
971
// and with a count of app versions
972
//
973
function get_app_types() {
974
    $t = new StdClass;
975
    $t->cpu = false;
976
    $t->cuda = false;
977
    $t->ati = false;
978
    $t->intel_gpu = false;
979
    $t->count = 0;
980
    $avs = BoincAppVersion::enum("deprecated=0");
981
    foreach ($avs as $av) {
982
        if (strstr($av->plan_class, "ati")) {
983
            $t->ati = true;
984
            $t->count++;
985
        } else if (strstr($av->plan_class, "amd")) {
986
            $t->ati = true;
987
            $t->count++;
988
        } else if (strstr($av->plan_class, "cuda")) {
989
            $t->cuda = true;
990
            $t->count++;
991
        } else if (strstr($av->plan_class, "nvidia")) {
992
            $t->cuda = true;
993
            $t->count++;
994
        } else if (strstr($av->plan_class, "intel_gpu")) {
995
            $t->intel_gpu = true;
996
            $t->count++;
997
        } else {
998
            $t->cpu = true;
999
            $t->count++;
1000
        }
1001
    }
1002
    return $t;
1003
}
1004
1005
// Functions to sanitize GET and POST args
1006
1007
// "next_url" arguments (must be local, not full URLs)
1008
//
1009
function sanitize_local_url($x) {
1010
    $x = trim($x, "/");
1011
    if (strstr($x, "/")) return "";
1012
    if (strstr($x, "<")) return "";
1013
    if (strstr($x, "\"")) return "";
1014
    return $x;
1015
}
1016
1017
// strip HTML tags
1018
//
1019
function sanitize_tags($x) {
1020
    return strip_tags($x);
1021
}
1022
1023
function sanitize_numeric($x) {
1024
    if (is_numeric($x)) {
1025
        return $x;
1026
    } else if (trim($x) == '' ) {
1027
        return '';
1028
    } else {
1029
        return "not numeric";
1030
    }
1031
}
1032
1033
function sanitize_email($x) {
1034
    if (function_exists('filter_var')) {
1035
        return filter_var($x, FILTER_SANITIZE_EMAIL);
1036
    } else {
1037
        return strip_tags($x);
1038
    }
1039
}
1040
1041
function flops_to_credit($f) {
1042
    return $f*(200/86400e9);
1043
}
1044
1045
function credit_to_gflop_hours($c) {
1046
    return $c/(200/24);
1047
}
1048
1049
function do_download($path,$name="") {
1050
    if (strcmp($name,"") == 0) {
1051
        $name=basename($path);
1052
    }
1053
    header('Content-Description: File Transfer');
1054
    header('Content-Type: application/octet-stream');
1055
    header('Content-Disposition: attachment; filename='.$name);
1056
    header('Content-Transfer-Encoding: binary');
1057
    header('Expires: 0');
1058
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1059
    header('Pragma: public');
1060
    header('Content-Length: ' . filesize($path));
1061
    flush();
1062
    readfile($path);
1063
}
1064
1065
// if have SSL but not using it, redirect
1066
//
1067
function redirect_to_secure_url() {
1068
    if (defined('SECURE_URL_BASE')
1069
        && strstr(SECURE_URL_BASE, "https://")
1070
        && empty($_SERVER['HTTPS'])
1071
    ) {
1072
        Header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
0 ignored issues
show
Coding Style introduced by
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
1073
        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...
1074
    }
1075
}
1076
1077
if (php_sapi_name() != "cli") {
1078
    redirect_to_secure_url();
1079
}
1080
1081
function badges_string($is_user, $item, $height) {
1082
    if (DISABLE_BADGES) return null;
1083
    if ($is_user) {
1084
        $bus = BoincBadgeUser::enum("user_id=$item->id");
1085
    } else {
1086
        $bus = BoincBadgeTeam::enum("team_id=$item->id");
1087
    }
1088
    if (!$bus) return null;
1089
    $x = "";
1090
    foreach ($bus as $bu) {
1091
        $badge = BoincBadge::lookup_id($bu->badge_id);
1092
        $x .= "<img title=\"$badge->title\" valign=top height=$height src=$badge->image_url> ";
1093
    }
1094
    return $x;
1095
}
1096
1097
function show_badges_row($is_user, $item) {
1098
    if (BADGE_HEIGHT_LARGE == 0) return;
0 ignored issues
show
introduced by
The condition BADGE_HEIGHT_LARGE == 0 is always false.
Loading history...
1099
    $x = badges_string($is_user, $item, BADGE_HEIGHT_LARGE);
1100
    if ($x) {
1101
        row2("Badges", $x);
1102
    }
1103
}
1104
1105
// If this request is from a BOINC client, return its version as MMmmRR.
1106
// Otherwise return 0.
1107
// Format of user agent string is "BOINC client (windows_x86_64 7.3.17)"
1108
//
1109
function boinc_client_version(){
1110
    if (!array_key_exists('HTTP_USER_AGENT', $_SERVER)) return 0;
1111
    $x = $_SERVER['HTTP_USER_AGENT'];
1112
    $e =  "/BOINC client [^ ]* (\d+).(\d+).(\d+)\)/";
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "="; 2 found
Loading history...
1113
    if (preg_match($e, $x, $matches)) {
1114
        return $matches[1]*10000 + $matches[2]*100 + $matches[3];
1115
    }
1116
    return 0;
1117
}
1118
1119
// output a script for counting chars left in text field
1120
//
1121
function text_counter_script() {
1122
    echo "<script type=\"text/javascript\">
1123
        function text_counter(field, countfield, maxlimit) {
1124
            if (field.value.length > maxlimit) {
1125
                field.value =field.value.substring(0, maxlimit);
1126
            } else {
1127
                countfield.value = maxlimit - field.value.length
1128
            }
1129
        }
1130
        </script>
1131
    ";
1132
}
1133
1134
// return HTML for a textarea with chars-remaining counter.
1135
// Call text_counter_script() before using this.
1136
//
1137
function textarea_with_counter($name, $maxlen, $text) {
1138
    $rem_name = $name."_remaining";
1139
    return "<textarea name=\"$name\" class=\"form-control\" rows=3 id=\"$name\" onkeydown=\"text_counter(this.form.$name, this.form.$rem_name, $maxlen);\"
1140
        onkeyup=\"text_counter(this.form.$name, this.form.$rem_name, $maxlen);\">".$text."</textarea>
1141
        <br><input name=\"$rem_name\" type=\"text\" id=\"$rem_name\" value=\"".($maxlen-strlen($text))."\" size=\"3\" maxlength=\"3\" readonly> ".tra("characters remaining")
1142
    ;
0 ignored issues
show
Coding Style introduced by
Space found before semicolon; expected ");" but found ")
;"
Loading history...
1143
}
1144
1145
// convert number MMmmrr to string MM.mm.rr
1146
//
1147
function version_string_maj_min_rel($v) {
1148
    $maj = (int)($v/10000);
1149
    $v -= $maj*10000;
1150
    $min = (int)($v/100);
1151
    $v -= $min*100;
1152
    return sprintf("%d.%d.%d", $maj, $min, $v);
1153
}
1154
1155
function google_search_form($url) {
1156
    echo "
1157
        <nobr>
1158
        <form method=get action=\"https://google.com/search\">
1159
        <input type=hidden name=domains value=\"$url\">
1160
        <input type=hidden name=sitesearch value=\"$url\">
1161
        <input name=q size=20>
1162
        <input type=submit value=".tra("Search").">
1163
        </form>
1164
        </nobr>
1165
    ";
1166
}
1167
1168
// use the following around text with long lines,
1169
// to limit the width and make it more readable.
1170
//
1171
function text_start($width=640) {
1172
    echo sprintf("<div style=\"max-width: %dpx;\">\n", $width);
1173
}
1174
function text_end() {
1175
    echo "</div>\n";
1176
}
1177
1178
// express a size in terms of GB or MB
1179
//
1180
function size_string($x) {
1181
    if ($x > GIGA) {
1182
        return number_format($x/GIGA, 2)." GB";
1183
    }
1184
    return number_format($x/MEGA, 2)." MB";
1185
}
1186
1187
function cert_filename() {
1188
    return defined("CERT_FILENAME")?CERT_FILENAME:"cert1.php";
1189
}
1190
1191
// if user hasn't validated their email addr, tell them to
1192
//
1193
function check_validated_email($user) {
1194
    if (!$user->email_validated) {
1195
        page_head("Please validate your email address");
1196
        echo "
1197
            To post here, please
1198
            <a href=validate_email_addr.php>validate your email address<a>.
1199
        ";
1200
        page_tail();
1201
        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...
1202
    }
1203
}
1204
1205
$cvs_version_tracker[]="\$Id$";  //Generated automatically - do not edit
1206
1207
?>
1208