Issues (1839)

html/inc/util.inc (49 issues)

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