Passed
Push — server_release/1/1.4 ( fdb43e...460c6a )
by
unknown
11:29
created

sanitize_user_url()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 8
nop 1
dl 0
loc 19
rs 9.2222
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
define('TERA', 1024*GIGA);
132
133
// return true if this page is HTTPS
134
//
135
function is_https() {
136
    return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'];
137
}
138
139
function secure_url_base() {
140
    if (defined('SECURE_URL_BASE')) return SECURE_URL_BASE;
141
    return URL_BASE;
142
}
143
144
function url_base() {
145
    return is_https()?secure_url_base():URL_BASE;
146
}
147
148
function send_cookie($name, $value, $permanent, $ops=false) {
149
    global $master_url;
150
151
    // the following allows independent login for projects on the same server
152
    //
153
    $url = parse_url($master_url);
154
    $path = $url['path'];
155
    if ($ops) {
156
        $path = substr($path, 0, -1);
157
        $path .= "_ops/";
158
    }
159
    $expire = $permanent?time()+3600*24*365:0;
160
    setcookie($name, $value, $expire, $path);
161
}
162
163
function clear_cookie($name, $ops=false) {
164
    global $master_url;
165
    $url = parse_url($master_url);
166
    $path = $url['path'];
167
    if ($ops) {
168
        $path = substr($path, 0, -1);
169
        $path .= "_ops/";
170
    }
171
    setcookie($name, '', time()-3600, $path);
172
}
173
174
$g_logged_in_user = null;
175
$got_logged_in_user = false;
176
177
function get_logged_in_user($must_be_logged_in=true) {
178
    global $g_logged_in_user, $got_logged_in_user;
179
    if ($got_logged_in_user) {
180
        // this could have been called earlier with $must_be_logged_in false
181
        if ($must_be_logged_in) {
182
            if ($g_logged_in_user) return $g_logged_in_user;
183
        } else {
184
            return $g_logged_in_user;
185
        }
186
    }
187
188
    if (web_stopped()) return null;
189
190
    $authenticator = null;
191
    if (isset($_COOKIE['auth'])) $authenticator = $_COOKIE['auth'];
192
193
    if ($authenticator) {
194
        $authenticator = BoincDb::escape_string($authenticator);
195
        $g_logged_in_user = BoincUser::lookup("authenticator='$authenticator'");
196
    }
197
    if ($must_be_logged_in && !$g_logged_in_user) {
198
        $next_url = '';
199
        if (array_key_exists('REQUEST_URI', $_SERVER)) {
200
            $next_url = $_SERVER['REQUEST_URI'];
201
            $n = strrpos($next_url, "/");
202
            if ($n) {
203
                $next_url = substr($next_url, $n+1);
204
            }
205
        }
206
        $next_url = urlencode($next_url);
207
        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...
208
        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...
209
    }
210
    $got_logged_in_user = true;
211
    return $g_logged_in_user;
212
}
213
214
function show_login_info($prefix="") {
215
    $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...
216
    if ($user) {
217
        $url_tokens = url_tokens($user->authenticator);
218
        echo "<nobr>$user->name &middot; <a href=".$prefix."logout.php?$url_tokens>".tra("log out")."</a></nobr>";
219
    } else {
220
        echo "<a href=".$prefix."login_form.php>".tra("log in")."</a>";
221
    }
222
}
223
224
$cache_control_extra="";
225
$is_login_page = false;
226
227
// Call this to start pages.
228
// Outputs some HTML boilerplate,
229
// then calls project_banner() (in html/project/project.inc)
230
// to output whatever you want at the top of your web pages.
231
//
232
// Page_head() is overridable so that projects that want to integrate BOINC
233
// with an existing web framework can more easily do so.
234
// To do so, define page_head() in the project include file.
235
//
236
if (!function_exists("page_head")){
237
function page_head(
238
    $title,
239
        // 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...
240
    $body_attrs=null,
241
        // <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...
242
        // 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...
243
        // (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...
244
        // 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...
245
    $is_main = false,
246
        // 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...
247
        // 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...
248
        // 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...
249
    $url_prefix="",
250
        // 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...
251
        // 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...
252
    $head_extra=null
253
        // 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...
254
        // 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...
255
        // 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...
256
) {
257
    global $caching, $cache_control_extra, $did_page_head;
258
    global $is_login_page, $fixed_navbar;
259
260
    if ($did_page_head) {
261
        return;
262
    }
263
    
264
    $did_page_head = true;
265
    $url_base = url_base();
266
267
    $rssname = "RSS 2.0";
268
    $rsslink = $url_base."rss_main.php";
269
270
    if (!$caching) {
271
        header("Content-type: text/html; charset=utf-8");
272
        header("Expires: Mon, 26 Jul 1997 05:00:00 UTC");
273
            // Date in the past
274
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " UTC");
275
            // always modified
276
        header("Cache-Control: $cache_control_extra no-cache, must-revalidate, post-check=0, pre-check=0");
277
            // for HTTP/1.1
278
        header("Pragma: no-cache");
279
            // for HTTP/1.0
280
    }
281
282
    echo '<!DOCTYPE html>
283
        <html lang="en">
284
        <head>
285
    ';
286
    if (defined('GLOBAL_HEAD_EXTRA')) {
287
        echo GLOBAL_HEAD_EXTRA;
288
    }
289
    echo '
290
        <meta name="viewport" content="width=device-width, initial-scale=1">
291
    ';
292
    if ($head_extra) {
293
        echo "\n$head_extra\n";
294
    }
295
    if ($is_main && (!defined('NO_COMPUTING')||!NO_COMPUTING)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space before logical operator; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after logical operator; 0 found
Loading history...
296
        readfile("schedulers.txt");
297
    }
298
299
    $t = $title?$title:PROJECT;
300
    echo "<title>$t</title>\n";
301
    echo '
302
        <meta charset="utf-8">
303
    ';
304
    if (DARK_MODE) {
305
        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...
306
<script>
307
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
308
      console.log("foobar");
309
    document.documentElement.style.display = 'none';
310
    document.head.insertAdjacentHTML(
311
        'beforeend',
312
        '<link rel="stylesheet" href="sample_bootstrap.min.css" onload="document.documentElement.style.display = \'\'"><link rel="stylesheet" href="custom.css">'
313
    );
314
  }
315
</script>
316
<link rel="stylesheet" href="bootstrap_darkly.min.css" media="(prefers-color-scheme: dark)">
317
<link rel="stylesheet" href="custom_dark.css" media="(prefers-color-scheme: dark)">
318
<link rel="stylesheet" href="sample_bootstrap.min.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">
319
<link rel="stylesheet" href="custom.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">
320
EOT;
321
    } else {
322
        echo '
323
            <link type="text/css" rel="stylesheet" href="'.secure_url_base().'/bootstrap.min.css" media="all">
324
        ';
325
    }
326
    if (defined('STYLESHEET')) {
327
        $stylesheet = $url_base.STYLESHEET;
328
        echo "
329
            <link rel=stylesheet type=\"text/css\" href=\"$stylesheet\">
330
        ";
331
    }
332
    if (defined('STYLESHEET2')) {
333
        $stylesheet2 = $url_base.STYLESHEET2;
334
        echo "
335
            <link rel=stylesheet type=\"text/css\" href=\"$stylesheet2\">
336
        ";
337
    }
338
339
    if (defined("SHORTCUT_ICON")) {
340
        echo '<link rel="icon" type="image/x-icon" href="'.SHORTCUT_ICON.'"/>
341
';
342
    }
343
344
    echo "
345
        <link rel=alternate type=\"application/rss+xml\" title=\"$rssname\" href=\"$rsslink\">
346
        </head>
347
    ";
348
    if ($fixed_navbar) {
349
        $body_attrs .= ' style="padding-top:70px"';
350
    }
351
    echo "<body $body_attrs>";
352
    display_cvs_versions();
353
    echo '<div class="container-fluid">
354
    ';
355
356
    switch($title) {    //kludge
357
    case tra("Log in"):
358
    case tra("Create an account"):
359
    case tra("Server status page"):
360
        $is_login_page = true;
361
        break;
362
    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...
363
        break;
364
    }
365
    project_banner($title, $url_prefix, $is_main);
366
}
367
}
368
369
// See the comments for page_head()
370
//
371
if (!function_exists("page_tail")){
372
function page_tail(
373
    $show_date=false,
374
        // 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...
375
    $url_prefix="",
376
        // 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...
377
    $is_main=false
378
        // 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...
379
) {
380
    echo "<br>\n";
381
    project_footer($is_main, $show_date, $url_prefix);
382
    echo '
383
        <script src="'.secure_url_base().'/jquery.min.js"></script>
384
        <script src="'.secure_url_base().'/bootstrap.min.js"></script>
385
        </div>
386
        </body>
387
        </html>
388
    ';
389
}
390
}
391
392
function display_cvs_versions(){
393
    global $cvs_version_tracker;
394
    echo "\n<!-- SVN VERSIONS -->\n";
395
    for ($i=0;$i<sizeof($cvs_version_tracker);$i++) {
0 ignored issues
show
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...
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...
396
        echo "<!-- ".$cvs_version_tracker[$i]." -->\n";
397
    }
398
}
399
400
function db_error_page() {
401
    page_head("Database error");
402
    echo tra("A database error occurred while handling your request; please try again later.");
403
    page_tail();
404
}
405
406
function error_page($msg) {
407
    global $generating_xml;
408
    if ($generating_xml) {
409
        xml_error(-1, $msg);
410
    }
411
    page_head(tra("Unable to handle request"));
412
    echo $msg;
413
    page_tail();
414
    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...
415
}
416
417
// takes argument in second and returns a human formatted time string
418
// in the form D days + h Hours + m Min + s sec.
419
420
function time_diff($x, $res=3) {
421
    $days    = (int)($x/86400);
422
    $hours   = (int)(($x-$days*86400)/3600);
423
    $minutes = (int)(($x-$days*86400-$hours*3600)/60);
424
    $seconds = (int)($x % 60);
425
426
    $datestring = "";
427
    if ($days) {
428
        $datestring .= "$days ".tra("days")." ";
429
    }
430
    if ($res>0 && ($hours || strlen($datestring))) {
431
        $datestring .= "$hours ".tra("hours")." ";
432
    }
433
    if ($res>1 && ($minutes || strlen($datestring))) {
434
        $datestring .= "$minutes ".tra("min")." ";
435
    }
436
    if ($res>2 && ($seconds)) {
437
        $datestring .= "$seconds ".tra("sec")." ";
438
    }
439
440
    return $datestring;
441
}
442
443
444
function date_str($x) {
445
    if ($x == 0) return "---";
446
    return gmdate('j M Y', $x);
447
}
448
449
function time_str($x) {
450
    if ($x == 0) return "---";
451
    return gmdate('j M Y, G:i:s', $x) . " UTC";
452
}
453
454
function local_time_str($x) {
455
    if ($x == 0) return "---";
456
    return date('j M Y, H:i T', $x);
457
}
458
459
function pretty_time_str($x) {
460
    return time_str($x);
461
}
462
463
function start_table_str($class="", $style="") {
464
    $s = $style?'style="'.$style.'"':'';
465
    return '<div class="table">
466
      <table '.$s.' width="100%" class="table table-condensed '.$class.'" >
467
    ';
468
}
469
470
function start_table($class="", $style="") {
471
    echo start_table_str($class, $style);
472
}
473
474
function end_table_str() {
475
    return '</table>
476
        </div>
477
    ';
478
}
479
480
function end_table() {
481
    echo end_table_str();
482
}
483
484
// Table header row with unlimited number of columns
485
486
function table_header() {
487
    echo "<tr>\n";
488
    $c = 'class="bg-primary"';
489
    for ($i = 0; $i < func_num_args(); $i++) {
490
        if (is_array(func_get_arg($i))) {
491
            $col = func_get_arg($i);
492
            echo "<th $c ".$col[1].">".$col[0]."</th>\n";
493
        } else {
494
            echo "<th $c>".func_get_arg($i)."</th>\n";
495
        }
496
    }
497
    echo "</tr>\n";
498
}
499
500
// Table row with unlimited number of columns
501
502
function table_row() {
503
    echo "<tr>\n";
504
    for ($i = 0; $i < func_num_args(); $i++) {
505
        if (is_array(func_get_arg($i))) {
506
            $col = func_get_arg($i);
507
            echo "<td ".$col[1].">".$col[0]."</td>\n";
508
        } else {
509
            echo "<td>".func_get_arg($i)."</td>\n";
510
        }
511
    }
512
    echo "</tr>\n";
513
}
514
515
function row1($x, $ncols=2, $class="heading") {
516
    if ($class == "heading") {
517
        echo "<tr><th class=\"bg-primary\" colspan=\"$ncols\">$x</th></tr>\n";
518
    } else {
519
        echo "<tr><td class=\"$class\" colspan=\"$ncols\">$x</td></tr>\n";
520
    }
521
}
522
523
define('NAME_ATTRS', 'class="text-right " style="padding-right:12px"');
524
define('VALUE_ATTRS', 'style="padding-left:12px"');
525
define('VALUE_ATTRS_ERR', 'class="danger" style="padding-left:12px"');
526
527
function row2($x, $y, $show_error=false, $lwidth='40%') {
528
    if ($x==="") $x="<br>";
529
    if ($y==="") $y="<br>";
530
    $attrs = $show_error?VALUE_ATTRS_ERR:VALUE_ATTRS;
531
    echo "<tr>
532
        <td width=\"$lwidth\" ".NAME_ATTRS.">$x</td>
533
        <td $attrs >$y</td>
534
        </tr>
535
    ";
536
}
537
538
function row2_init($x, $y, $lwidth='40%') {
539
    echo '<tr>
540
        <td class="text-right " width="'.$lwidth.'"  style="padding-right: 20px;">'.$x.'</td>
541
        <td '.VALUE_ATTRS.'>'.$y.'
542
    ';
543
}
544
545
function row2_plain($x, $y) {
546
    echo "<tr><td>$x</td><td>$y</td></tr>\n";
547
}
548
549
function rowify($string) {
550
    echo "<tr><td>$string</td></tr>";
551
}
552
553
function row_array($x) {
554
    echo "<tr>\n";
555
    foreach ($x as $h) {
556
        echo "<td>$h</td>\n";
557
    }
558
    echo "</tr>\n";
559
}
560
561
define ('ALIGN_RIGHT', 'style="text-align:right;"');
562
563
function row_heading_array($x, $attrs=null, $class='bg-primary') {
564
    echo "<tr>";
565
    $i = 0;
566
    foreach ($x as $h) {
567
        $a = $attrs?$attrs[$i]:"";
568
        echo "<th $a class=\"$class\">$h</th>";
569
        $i++;
570
    }
571
    echo "</tr>\n";
572
}
573
574
function row_heading($x, $class='bg-primary') {
575
    echo sprintf('<tr><th class="%s" colspan=99>%s</th></tr>
576
        ', $class, $x
577
    );
578
}
579
580
function url_tokens($auth) {
581
    $now = time();
582
    $ttok = md5((string)$now.$auth);
583
    return "&amp;tnow=$now&amp;ttok=$ttok";
584
}
585
586
function form_tokens($auth) {
587
    $now = time();
588
    $ttok = md5((string)$now.$auth);
589
    return "<input type=\"hidden\" name=\"tnow\" value=\"$now\">
590
        <input type=\"hidden\" name=\"ttok\" value=\"$ttok\">
591
    ";
592
}
593
594
function valid_tokens($auth) {
595
    $tnow = get_str('tnow', true);
596
    $ttok = get_str('ttok', true);
597
    if (!$tnow) {
598
      if (isset($_POST['tnow'])) {
599
          $tnow = $_POST['tnow'];
600
      }
601
    }
602
    if (!$ttok) {
603
      if (isset($_POST['ttok'])) {
604
          $ttok = $_POST['ttok'];
605
      }
606
    }
607
    if (!$tnow) return false;
608
    if (!$ttok) return false;
609
    $t = md5((string)$tnow.$auth);
610
    if ($t != $ttok) return false;
611
    if (time() > $tnow + 86400) return false;
612
    return true;
613
}
614
615
function check_tokens($auth) {
616
    if (valid_tokens($auth)) return;
617
    error_page(
618
        tra("Link has timed out. Please click Back, refresh the page, and try again.")
619
    );
620
}
621
622
// Generates a legal filename from a parameter string.
623
624
function get_legal_filename($name) {
625
    return strtr($name, array(','=>'', ' '=>'_'));
626
}
627
628
// Returns a string containing as many words
629
// (being collections of characters separated by the character $delimiter)
630
// as possible such that the total string length is <= $chars characters long.
631
// If $ellipsis is true, then an ellipsis is added to any sentence which
632
// is cut short.
633
634
function sub_sentence($sentence, $delimiter, $max_chars, $ellipsis=false) {
635
    $words = explode($delimiter, $sentence);
636
    $total_chars = 0;
637
    $trunc = false;
638
    $result = "";
639
640
    foreach ($words as $word) {
641
        if (strlen($result) + strlen($word) > $max_chars) {
642
            $trunc = true;
643
            break;
644
        }
645
        if ($result) {
646
            $result .= " $word";
647
        } else {
648
            $result = $word;
649
        }
650
    }
651
652
    if ($ellipsis && $trunc) {
653
        $result .= "...";
654
    }
655
656
    return $result;
657
}
658
659
// use this for user RAC and result credit
660
//
661
function format_credit($x) {
662
    return number_format($x, 2);
663
}
664
665
// use this when credit is likely to be large, e.g. team RAC
666
//
667
function format_credit_large($x) {
668
    return number_format($x, 0);
669
}
670
671
function host_link($hostid) {
672
    if ($hostid) {
673
        return "<a href=\"show_host_detail.php?hostid=$hostid\">$hostid</a>";
674
    } else {
675
        return "---";
676
    }
677
}
678
679
function open_output_buffer() {
680
    ob_start();
681
    ob_implicit_flush(0);
682
}
683
684
function close_output_buffer($filename) {
685
    $fh = fopen($filename, "w");
686
    $page = ob_get_contents();
687
    ob_end_clean();
688
    fwrite($fh, $page);
689
    fclose($fh);
690
}
691
692
function bbcode_info() {
693
    return "<br><a href=bbcode.php target=new><small>".tra("Use BBCode tags to format your text")."</small></a>\n";
694
}
695
696
// strip slashes if magic quotes in effect
697
function undo_magic_quotes($x) {
698
    if (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) {
699
        return stripslashes($x);
700
    }
701
    return $x;
702
}
703
704
// check for bogus GET args
705
//
706
function check_get_args($args) {
707
    foreach ($_GET as $key => $val) {
708
        if (!in_array($key, $args)) {
709
            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...
710
            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...
711
        }
712
    }
713
}
714
715
// returns null if the arg is optional and missing
716
//
717
function get_int($name, $optional=false) {
718
    $x=null;
719
    if (isset($_GET[$name])) $x = $_GET[$name];
720
    if (!is_numeric($x)) {
721
        if ($optional) {
722
            if ($x) {
723
                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...
724
                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...
725
            }
726
            return null;
727
        } else {
728
            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...
729
            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...
730
        }
731
    }
732
    return (int)$x;
733
}
734
735
// returns null if the arg is optional and missing
736
//
737
function post_num($name, $optional=false) {
738
    $x = null;
739
    if (isset($_POST[$name])) $x = $_POST[$name];
740
    if (!is_numeric($x)) {
741
        if ($optional) {
742
            return null;
743
        } else {
744
            error_page("missing or bad parameter: $name; supplied: ".htmlspecialchars($x));
745
        }
746
    }
747
    return (double)$x;
748
}
749
750
// returns null if the arg is optional and missing
751
//
752
function post_int($name, $optional=false) {
753
    $x = post_num($name, $optional);
754
    if (is_null($x)) return null;
755
    $y = (int)$x;
756
    if ($x != $y) {
757
        error_page("param $name must be an integer");
758
    }
759
    return $y;
760
}
761
762
function get_array($name) {
763
    if (isset($_GET[$name])) {
764
        return $_GET[$name];
765
    } else {
766
        return array();
767
    }
768
}
769
770
function get_str($name, $optional=false) {
771
    if (isset($_GET[$name])) {
772
        $x = $_GET[$name];
773
    } else {
774
        if (!$optional) {
775
            error_page("missing or bad parameter: $name");
776
        }
777
        $x = null;
778
    }
779
    return undo_magic_quotes($x);
780
}
781
782
function post_str($name, $optional=false) {
783
    if (isset($_POST[$name])) {
784
        $x = $_POST[$name];
785
    } else {
786
        if (!$optional) {
787
            error_page("missing or bad parameter: $name");
788
        }
789
        $x = null;
790
    }
791
    return undo_magic_quotes($x);
792
}
793
794
function post_arr($name, $optional=false) {
795
    if (isset($_POST[$name]) && is_array($_POST[$name])) {
796
        $x = $_POST[$name];
797
    } else {
798
        if (!$optional) {
799
            error_page("missing or bad parameter: $name");
800
        }
801
        $x = null;
802
    }
803
    return $x;
804
}
805
806
function is_ascii($str) {
807
    // the mb_* functions are not included by default
808
    // return (mb_detect_encoding($passwd) -= 'ASCII');
809
810
    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...
811
        $c = ord(substr($str, $i));
812
        if ($c < 32 || $c > 127) return false;
813
    }
814
    return true;
815
}
816
817
// This function replaces some often made mistakes while entering numbers
818
// and gives back an error if there are false characters
819
// It will also be checked if the value is within certain borders
820
// @param string &$value reference to the value that should be verified
821
// @param double $low the lowest number of value if verified
822
// @param double $high the highest number of value if verified
823
// @return bool true if $value is numeric and within the defined borders,
824
//   false if $value is not numeric, no changes were made in this case
825
//
826
function verify_numeric(&$value, $low, $high = false) {
827
    $number = trim($value);
828
    $number = str_replace('o', '0', $number);
829
    $number = str_replace('O', '0', $number);
830
    $number = str_replace('x', '', $number); //if someone enters '0x100'
831
    $number = str_replace(',', '.', $number); // replace the german decimal separator
832
    // if no value was entered and this is ok
833
    //
834
    if ($number=='' && !$low) return true;
835
836
    // the supplied value contains alphabetic characters
837
    //
838
    if (!is_numeric($number)) return false;
839
840
    if ($number < $low) return false;
841
842
    if ($high) {
843
        if ($number > $high) return false;
844
    }
845
    $value = (double)$number;
846
    return true;
847
}
848
849
// Generate a "select" element from an array of values
850
//
851
function select_from_array($name, $array, $selection=null, $width=240) {
852
    $out = '<select style="color:#000;"class="form-control input-sm" style="width:'.$width.'px" name="'.$name.'">"';
853
854
    foreach ($array as $key => $value) {
855
        if ($value) {
856
            $out .= "<option ";
857
            if ($key == $selection) {
858
                $out .= "selected ";
859
            }
860
            $out .= "value=\"".$key."\">".$value."</option>\n";
861
        }
862
    }
863
    $out .= "</select>\n";
864
    return $out;
865
}
866
867
// Convert to entities, while preserving already-encoded entities.
868
// Do NOT use if $str contains valid HTML tags.
869
//
870
function boinc_htmlentities($str) {
871
    $str = html_entity_decode($str, ENT_COMPAT, "UTF-8");
872
    $str = htmlentities($str, ENT_COMPAT, "UTF-8");
873
    return $str;
874
}
875
876
function strip_bbcode($string){
877
    return preg_replace("/((\[.+\])+?)(.+?)((\[\/.+\])+?)/","",$string);
878
}
879
880
function current_url() {
881
    $url = "http";
882
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") {
883
        $url .= "s";
884
    }
885
    $url .= "://";
886
    $url .= $_SERVER['SERVER_NAME'];
887
    $url .= ":".$_SERVER['SERVER_PORT'];
888
    if (isset($_SERVER['REQUEST_URI'])) {
889
        $url .= $_SERVER['REQUEST_URI'];
890
    } else {
891
        if ($_SERVER['QUERY_STRING']) {
892
            $url .= "?".$_SERVER['QUERY_STRING'];
893
        }
894
    }
895
    return $url;
896
}
897
898
// Show a single link formatted to look like a button.
899
// @param url The destination URL of the button
900
// @param text The text to display on the button
901
// @param desc The title of the destination - typically used as a popup
902
// @param class The optional CSS class of the button. Defaults to a standard button
903
//
904
905
function button_text($url, $text, $desc=null, $class="btn-success btn-sm") {
906
    if (!$desc) {
907
        $desc = $text;
908
    }
909
    return sprintf(' <a href="%s" title="%s" class="btn %s">%s</a>',
910
        $url, $desc, $class, $text
911
    );
912
}
913
914
function show_button($url, $text, $desc=null, $class="btn-success btn-sm") {
915
    echo button_text($url, $text, $desc, $class);
916
}
917
918
// for places with a bunch of buttons, like forum posts
919
//
920
function show_button_small($url, $text, $desc=null) {
921
    echo button_text($url, $text, $desc, "btn-primary btn-xs");
922
}
923
924
// used for showing icons
925
//
926
function show_image($src, $title, $alt, $height=null) {
927
    $h = "";
928
    if ($height) {
929
        $h = "height=\"$height\"";
930
    }
931
    echo "<img class=\"icon\" border=\"0\" title=\"$title\" alt=\"$alt\" src=\"$src\" $h>";
932
}
933
934
function show_project_down() {
935
    global $did_page_head;
936
    if (!$did_page_head) {
937
        page_head(tra("Project down for maintenance"));
938
    }
939
    echo tra(
940
        "%1 is temporarily shut down for maintenance.  Please try again later.",
941
        PROJECT
942
    );
943
    page_tail();
944
    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...
945
}
946
947
function check_web_stopped() {
948
    global $generating_xml;
949
    if (web_stopped()) {
950
        if ($generating_xml) {
951
            xml_error(-183);
952
        } else {
953
            show_project_down();
954
        }
955
    }
956
}
957
958
// Connects to database server and selects database as noted in config.xml
959
// If only read-only access is necessary,
960
// tries instead to connect to <replica_db_host> if tag exists.
961
// DEPRECATED - use boinc_db.inc
962
//
963
function db_init($try_replica=false) {
964
    check_web_stopped();
965
    $retval = db_init_aux($try_replica);
966
    if ($retval == 1) {
967
        echo tra("Unable to connect to database - please try again later");
968
        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...
969
    }
970
    if ($retval == 2) {
971
        echo tra("Unable to select database - please try again later");
972
        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...
973
    }
974
    return 0;
975
}
976
977
// return a structure indicating whether project has non-deprecated
978
// apps versions for various resource types,
979
// and with a count of app versions
980
//
981
function get_app_types() {
982
    $t = new StdClass;
983
    $t->cpu = false;
984
    $t->cuda = false;
985
    $t->ati = false;
986
    $t->intel_gpu = false;
987
    $t->count = 0;
988
    $avs = BoincAppVersion::enum("deprecated=0");
989
    foreach ($avs as $av) {
990
        if (strstr($av->plan_class, "ati")) {
991
            $t->ati = true;
992
            $t->count++;
993
        } else if (strstr($av->plan_class, "amd")) {
994
            $t->ati = true;
995
            $t->count++;
996
        } else if (strstr($av->plan_class, "cuda")) {
997
            $t->cuda = true;
998
            $t->count++;
999
        } else if (strstr($av->plan_class, "nvidia")) {
1000
            $t->cuda = true;
1001
            $t->count++;
1002
        } else if (strstr($av->plan_class, "intel_gpu")) {
1003
            $t->intel_gpu = true;
1004
            $t->count++;
1005
        } else {
1006
            $t->cpu = true;
1007
            $t->count++;
1008
        }
1009
    }
1010
    return $t;
1011
}
1012
1013
// Functions to sanitize GET and POST args
1014
1015
// "next_url" arguments (must be local, not full URLs)
1016
//
1017
function sanitize_local_url($x) {
1018
    $x = trim($x, "/");
1019
    if (strstr($x, "/")) return "";
1020
    if (strstr($x, "<")) return "";
1021
    if (strstr($x, "\"")) return "";
1022
    return $x;
1023
}
1024
1025
function sanitize_user_url($x) {
1026
    // if protocol is given, must be http: or https:
1027
    $y = explode('//', $x);
1028
    switch (count($y)) {
1029
    case 1:
1030
        $z = $x;
1031
        break;
1032
    case 2:
1033
        $z = $y[1];
1034
        if (strtolower($y[0]) == 'http:') break;
1035
        if (strtolower($y[0]) == 'https:') break;
1036
        return '';
1037
    default: return '';
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
Blank lines are not allowed after DEFAULT statements
Loading history...
1038
    }
1039
    // everything else must be alphanumeric, or -_/.#?&=
1040
    if (preg_match('/^[-_.\/#?&=a-zA-Z0-9]*$/', $z)) {
1041
        return $x;
1042
    }
1043
    return '';
1044
}
1045
1046
// strip HTML tags
1047
//
1048
function sanitize_tags($x) {
1049
    if (!$x) return $x;
1050
    return strip_tags($x);
1051
}
1052
1053
function sanitize_numeric($x) {
1054
    if (is_numeric($x)) {
1055
        return $x;
1056
    } else if (trim($x) == '' ) {
1057
        return '';
1058
    } else {
1059
        return "not numeric";
1060
    }
1061
}
1062
1063
function sanitize_email($x) {
1064
    if (!$x) return $x;
1065
    if (function_exists('filter_var')) {
1066
        return filter_var($x, FILTER_SANITIZE_EMAIL);
1067
    } else {
1068
        return strip_tags($x);
1069
    }
1070
}
1071
1072
function flops_to_credit($f) {
1073
    return $f*(200/86400e9);
1074
}
1075
1076
function credit_to_gflop_hours($c) {
1077
    return $c/(200/24);
1078
}
1079
1080
function do_download($path,$name="") {
1081
    if (strcmp($name,"") == 0) {
1082
        $name=basename($path);
1083
    }
1084
    header('Content-Description: File Transfer');
1085
    header('Content-Type: application/octet-stream');
1086
    header('Content-Disposition: attachment; filename='.$name);
1087
    header('Content-Transfer-Encoding: binary');
1088
    header('Expires: 0');
1089
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1090
    header('Pragma: public');
1091
    header('Content-Length: ' . filesize($path));
1092
    flush();
1093
    readfile($path);
1094
}
1095
1096
// if have SSL but not using it, redirect
1097
//
1098
function redirect_to_secure_url() {
1099
    if (defined('SECURE_URL_BASE')
1100
        && strstr(SECURE_URL_BASE, "https://")
1101
        && empty($_SERVER['HTTPS'])
1102
    ) {
1103
        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...
1104
        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...
1105
    }
1106
}
1107
1108
if (php_sapi_name() != "cli") {
1109
    redirect_to_secure_url();
1110
}
1111
1112
function badges_string($is_user, $item, $height) {
1113
    if (DISABLE_BADGES) return null;
1114
    if ($is_user) {
1115
        $bus = BoincBadgeUser::enum("user_id=$item->id");
1116
    } else {
1117
        $bus = BoincBadgeTeam::enum("team_id=$item->id");
1118
    }
1119
    if (!$bus) return null;
1120
    $x = "";
1121
    foreach ($bus as $bu) {
1122
        $badge = BoincBadge::lookup_id($bu->badge_id);
1123
        $x .= "<img title=\"$badge->title\" valign=top height=$height src=$badge->image_url> ";
1124
    }
1125
    return $x;
1126
}
1127
1128
function show_badges_row($is_user, $item) {
1129
    if (BADGE_HEIGHT_LARGE == 0) return;
0 ignored issues
show
introduced by
The condition BADGE_HEIGHT_LARGE == 0 is always false.
Loading history...
1130
    $x = badges_string($is_user, $item, BADGE_HEIGHT_LARGE);
1131
    if ($x) {
1132
        row2("Badges", $x);
1133
    }
1134
}
1135
1136
// If this request is from a BOINC client, return its version as MMmmRR.
1137
// Otherwise return 0.
1138
// Format of user agent string is "BOINC client (windows_x86_64 7.3.17)"
1139
//
1140
function boinc_client_version(){
1141
    if (!array_key_exists('HTTP_USER_AGENT', $_SERVER)) return 0;
1142
    $x = $_SERVER['HTTP_USER_AGENT'];
1143
    $e =  "/BOINC client [^ ]* (\d+).(\d+).(\d+)\)/";
0 ignored issues
show
Coding Style introduced by
Expected 1 space after "="; 2 found
Loading history...
1144
    if (preg_match($e, $x, $matches)) {
1145
        return $matches[1]*10000 + $matches[2]*100 + $matches[3];
1146
    }
1147
    return 0;
1148
}
1149
1150
// output a script for counting chars left in text field
1151
//
1152
function text_counter_script() {
1153
    echo "<script type=\"text/javascript\">
1154
        function text_counter(field, countfield, maxlimit) {
1155
            if (field.value.length > maxlimit) {
1156
                field.value =field.value.substring(0, maxlimit);
1157
            } else {
1158
                countfield.value = maxlimit - field.value.length
1159
            }
1160
        }
1161
        </script>
1162
    ";
1163
}
1164
1165
// return HTML for a textarea with chars-remaining counter.
1166
// Call text_counter_script() before using this.
1167
//
1168
function textarea_with_counter($name, $maxlen, $text) {
1169
    $rem_name = $name."_remaining";
1170
    return "<textarea name=\"$name\" class=\"form-control\" rows=3 id=\"$name\" onkeydown=\"text_counter(this.form.$name, this.form.$rem_name, $maxlen);\"
1171
        onkeyup=\"text_counter(this.form.$name, this.form.$rem_name, $maxlen);\">".$text."</textarea>
1172
        <br><input name=\"$rem_name\" type=\"text\" id=\"$rem_name\" value=\"".($maxlen-strlen($text))."\" size=\"3\" maxlength=\"3\" readonly> ".tra("characters remaining")
1173
    ;
0 ignored issues
show
Coding Style introduced by
Space found before semicolon; expected ");" but found ")
;"
Loading history...
1174
}
1175
1176
// convert number MMmmrr to string MM.mm.rr
1177
//
1178
function version_string_maj_min_rel($v) {
1179
    $maj = (int)($v/10000);
1180
    $v -= $maj*10000;
1181
    $min = (int)($v/100);
1182
    $v -= $min*100;
1183
    return sprintf("%d.%d.%d", $maj, $min, $v);
1184
}
1185
1186
function google_search_form($url) {
1187
    echo "
1188
        <nobr>
1189
        <form method=get action=\"https://google.com/search\">
1190
        <input type=hidden name=domains value=\"$url\">
1191
        <input type=hidden name=sitesearch value=\"$url\">
1192
        <input name=q size=20>
1193
        <input type=submit value=".tra("Search").">
1194
        </form>
1195
        </nobr>
1196
    ";
1197
}
1198
1199
// use the following around text with long lines,
1200
// to limit the width and make it more readable.
1201
//
1202
function text_start($width=640) {
1203
    echo sprintf("<div style=\"max-width: %dpx;\">\n", $width);
1204
}
1205
function text_end() {
1206
    echo "</div>\n";
1207
}
1208
1209
// express a size in terms of GB or MB
1210
//
1211
function size_string($x) {
1212
    if ($x > TERA) {
1213
        return number_format($x/TERA, 2)." TB";
1214
    }
1215
    if ($x > GIGA) {
1216
        return number_format($x/GIGA, 2)." GB";
1217
    }
1218
    return number_format($x/MEGA, 2)." MB";
1219
}
1220
1221
function cert_filename() {
1222
    return defined("CERT_FILENAME")?CERT_FILENAME:"cert1.php";
1223
}
1224
1225
// if user hasn't validated their email addr, tell them to
1226
//
1227
function check_validated_email($user) {
1228
    if (!$user->email_validated) {
1229
        page_head("Please validate your email address");
1230
        echo "
1231
            To post here, please
1232
            <a href=validate_email_addr.php>validate your email address<a>.
1233
        ";
1234
        page_tail();
1235
        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...
1236
    }
1237
}
1238
1239
$cvs_version_tracker[]="\$Id$";  //Generated automatically - do not edit
1240
1241
?>
1242