Issues (1839)

html/inc/util_ops.inc (2 issues)

1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2017 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 admin web pages
20
21
require_once("../inc/db_ops.inc");
22
require_once("../inc/util.inc");
23
require_once("../project/project.inc");
24
25
display_errors();
26
27
function admin_page_head($title) {
28
    echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">";
29
    echo sprintf('<html><head><title>%s</title>
30
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
31
        <link type="text/css" rel="stylesheet" href="%s/bootstrap.min.css" media="all">
32
        <link type="text/css" rel="stylesheet" href="%s/custom.css" media="all">
33
        </head>
34
        <body>
35
        <div class="container-fluid">
36
        <h2>%s: %s</h2>
37
        ',
38
        $title,
39
        secure_url_base(),
40
        secure_url_base(),
41
        PROJECT,
42
        $title
43
    );
44
    show_login_info();
45
    echo "<p>";
46
}
47
48
function admin_page_tail() {
49
    echo sprintf('
50
        <hr><center><a href=index.php>Main page</a></center>
51
        <script src="%s/jquery.min.js"></script>
52
        <script src="%s/bootstrap.min.js"></script>
53
        </div>
54
        </body>
55
        </html>
56
        ',
57
        secure_url_base(),
58
        secure_url_base()
59
    );
60
}
61
62
// TODO: get rid of all the following
63
64
function print_checkbox($text,$name,$checked) {
65
    echo "<input type=\"checkbox\" name=\"$name\""
66
        . (strlen($checked) ? " checked=\"checked\"" : "") . ">"
67
        . "$text\n"
68
        . "<p>\n";
69
}
70
71
function print_radio_button($text,$name,$value,$checked) {
72
    echo "<input type=\"radio\" name=\"$name\" value=\"$value\""
73
        . (strlen($checked) ? " checked=\"checked\"" : "") . ">"
74
        . "$text\n"
75
        . "<br>\n";
76
}
77
78
function print_text_field($text,$name,$value) {
79
    echo "$text <input type=\"text\" size=\"10\" name=\"$name\" value=\"$value\">\n"
80
         . "<p>\n";
81
}
82
83
function row($x, $y) {
84
    echo "<tr><td width=30% valign=\"top\" align=\"right\">$x &nbsp;&nbsp; </td>\n<td>$y</td>\n</tr>\n";
85
}
86
87
function c_row2($color, $x, $y) {
88
    echo "<tr bgcolor=\"$color\"><td align=\"right\">$x</td><td>$y</td></tr>\n";
89
}
90
91
function show_profile_link_ops($user) {
92
    if ($user->has_profile) {
93
        row2("Profile",
94
            "<a href=\"".url_base()."view_profile.php?userid=$user->id\">View</a>"
95
        );
96
    }
97
}
98
99
// initialize database connection with username & password from
100
// command line instead of config.xml
101
//
102
function db_init_cli() {
103
    $config = get_config();
104
    $db_name = parse_config($config, "<db_name>");
105
    $host = parse_config($config, "<db_host>");
106
    if ($host == null) {
107
        $host = "localhost";
108
    }
109
    $in = fopen("php://stdin","r");
110
    print "Database username (default: owner of mysqld process): ";
111
    $user = rtrim(fgets($in, 80));
112
    print "Database password (if any): ";
113
    $pass = rtrim(fgets($in, 80));
114
115
    $retval = _mysql_connect($host, $user, $pass, $db_name);
116
    if (!$retval) {
117
        die("Can't connect to DB\n");
118
    }
119
}
120
121
function print_login_form_ops($next_url='') {
122
    if ($next_url == '') $next_url = $_SERVER['REQUEST_URI'];
123
    start_table();
124
    echo "
125
        <form method=post action=login_action.php>
126
        <input type=hidden name=next_url value=$next_url>
127
    ";
128
    row2("Email", "<input name=email_addr size=40>");
129
    row2("Password", "<input type=password name=passwd size=40>");
130
    row2(tra("Stay logged in on this computer"), '<input type="checkbox" name="stay_logged_in" checked>');
131
    row2("", "<input class=\"btn btn-primary\" type=submit value=OK>");
132
    end_table();
133
}
134
135
function get_logged_in_user_ops() {
136
    global $g_logged_in_user;
137
    if ($g_logged_in_user) return $g_logged_in_user;
138
    $authenticator = null;
139
    if (isset($_COOKIE['auth'])) $authenticator = $_COOKIE['auth'];
140
141
    $authenticator = BoincDb::escape_string($authenticator);
142
    if ($authenticator) {
143
        $g_logged_in_user = BoincUser::lookup("authenticator='$authenticator'");
144
    }
145
    return $g_logged_in_user;
146
}
147
148
////////// functions for access control of admin web pages /////////////
149
150
// allow access only if logged in as user in a given set
151
//
152
function auth_ops_userid($admin_user_ids) {
153
    $user = get_logged_in_user_ops();
154
    if (!$user) {
155
        admin_page_head("Log in");
156
        echo "You must log in to performance admin functions.<p>\n";
157
        print_login_form_ops();
158
        admin_page_tail();
159
        exit;
160
    } else if (!in_array($user->id, $admin_user_ids)) {
161
        admin_page_head("Log in");
162
        echo "
163
            You must be logged in as an admin to perform admin functions.
164
            <p>
165
            <a href=logout.php>Log out</a>
166
        ";
167
        admin_page_tail();
168
        exit;
169
    }
170
}
171
172
// allow access only to users with ADMIN/DEV flags in forum prefs.
173
// If you use this, make sure you know who has these privileges
174
//
175
function auth_ops_privilege() {
176
    $user = get_logged_in_user_ops();
177
    if (!$user) {
178
        admin_page_head("Log in");
179
        echo "You must log in to performance admin functions.<p>\n";
180
        print_login_form_ops();
181
        admin_page_tail();
182
        exit;
183
    }
184
    BoincForumPrefs::lookup($user);
185
    if ($user->prefs->privilege(S_ADMIN) || $user->prefs->privilege(S_DEV)) {
186
        return;
187
    }
188
    error_page("Access denied");
189
}
190
191
// if project hasn't specified a policy in project.inc,
192
// and no .htaccess, don't allow access
193
//
194
if (!function_exists('auth_ops')) {
195
    function auth_ops() {
196
        if (!file_exists(".htaccess")) {
197
            error_page("
198
                You must protect the admin interface
199
                with either a .htaccess file or an auto_ops() function.
200
                <p>
201
                <a href=https://github.com/BOINC/boinc/wiki/HtmlOps>See how here</a>"
202
            );
203
        }
204
    }
205
}
206
207
function admin_error_page($msg) {
208
    admin_page_head("Unable to handle request");
209
    echo $msg;
210
    admin_page_tail();
211
    exit;
212
}
213
214
// given a list of app versions,
215
// return a list of the current, non-deprecated ones
216
//
217
function current_versions($avs) {
218
    foreach($avs as $av) {
219
        foreach ($avs as $av2) {
220
            if ($av->id == $av2->id) continue;
221
            if ($av->platformid == $av2->platformid && $av->plan_class == $av2->plan_class && $av->version_num > $av2->version_num) {
222
                $av2->deprecated = 1;
223
            }
224
        }
225
    }
226
    $x = array();
227
    foreach($avs as $av) {
228
        if (!$av->deprecated) $x[] = $av;
229
    }
230
    return $x;
231
}
232
233
// cancel WUs with IDs in a given range.
234
// This means:
235
//
236
// - for any results w/ server state UNSENT, set server state to OVER
237
// - set the CANCELLED bit in workunit.error_mask
238
//
239
function cancel_wus($wuid1, $wuid2) {
240
    $retval = BoincResult::update_aux("server_state=5, outcome=5 where server_state=2 and $wuid1<=workunitid and workunitid<=$wuid2");
241
    if (!$retval) {
242
        error_page("Result update failed");
243
    }
244
    $retval = BoincWorkunit::update_aux("error_mask=error_mask|16 where $wuid1<=id and id<=$wuid2");
245
    if (!$retval) {
246
        error_page("Workunit update failed");
247
    }
248
249
    // trigger the transitioner (it will set file_delete_state)
250
251
    $now = time();
252
    $retval = BoincWorkunit::update_aux("transition_time=$now where $wuid1<=id and id<=$wuid2");
253
    return 0;
254
}
255
256
// like above, but if a workunit has a result that's already sent,
257
// don't cancel the workunit
258
//
259
function cancel_wus_if_unsent($id1, $id2) {
260
    $wus = BoincWorkunit::enum("id >= $id1 and id <= $id2");
261
    foreach ($wus as $wu) {
262
        $results = BoincResult::enum("workunitid=$wu->id and server_state > 2");
263
        if (count($results)) continue;
264
        $retval = BoincResult::update_aux("server_state=5, outcome=5 where workunitid=$wu->id");
265
        if (!$retval) {
266
            error_page("result update failed");
267
        }
268
        if (!$wu->update("error_mask=error_mask|16")) {
269
            error_page("WU update failed");
270
        }
271
    }
272
    return 0;
273
}
274
275
function app_version_desc($avid) {
276
    switch ($avid) {
277
    case ANON_PLATFORM_UNKNOWN:
278
        return "Anonymous platform: unknown type";
279
    case ANON_PLATFORM_CPU:
280
        return "Anonymous platform: CPU";
281
    case ANON_PLATFORM_NVIDIA:
282
        return "Anonymous platform: NVIDIA GPU";
283
    case ANON_PLATFORM_ATI:
284
        return "Anonymous platform: AMD GPU";
285
    case ANON_PLATFORM_INTEL_GPU:
286
        return "Anonymous platform: Intel GPU";
287
    case ANON_PLATFORM_APPLE_GPU:
288
        return "Anonymous platform: Apple GPU";
289
    }
290
    if ($avid <= 0) {
291
        return "unknown: $avid";
292
    }
293
    $av = BoincAppVersion::lookup_id($avid);
294
    if ($av) {
295
        $p = BoincPlatform::lookup_id($av->platformid);
296
        if ($p) {
297
            return sprintf("%.2f", $av->version_num/100)." $p->name [$av->plan_class]";
298
        } else {
299
            return sprintf("%.2f", $av->version_num/100)." MISSING PLATFORM $av->platformid [$av->plan_class]";
300
        }
301
    } else {
302
        return "App version missing ($avid)";
303
    }
304
}
305
306
////// badge-related stuff
307
308
function get_badge($name, $title, $image_url) {
309
    $b = BoincBadge::lookup("name='$name'");
310
    if ($b) return $b;
311
    $now = time();
312
    $id = BoincBadge::insert("(create_time, type, name, title, description, image_url, level, tags, sql_rule) values ($now, 0, '$name', '$title', '', 'img/$image_url', '', '', '')");
313
    $b = BoincBadge::lookup_id($id);
314
    if ($b) return $b;
315
    die("can't create badge $name\n");
316
}
317
318
function assign_badge($is_user, $item, $badge) {
319
    $now = time();
320
    if ($is_user) {
321
        $bbu = BoincBadgeUser::lookup("user_id=$item->id and badge_id=$badge->id");
322
        if ($bbu) {
323
            $bbu->update("reassign_time=$now where user_id=$item->id and badge_id=$badge->id");
324
        } else {
325
            BoincBadgeUser::insert("(create_time, user_id, badge_id, reassign_time) values ($now, $item->id, $badge->id, $now)");
326
        }
327
    } else {
328
        $bbt = BoincBadgeTeam::lookup("team_id=$item->id and badge_id=$badge->id");
329
        if ($bbt) {
330
            $bbt->update("reassign_time=$now where team_id=$item->id and badge_id=$badge->id");
331
        } else {
332
            BoincBadgeTeam::insert("(create_time, team_id, badge_id, reassign_time) values ($now, $item->id, $badge->id, $now)");
333
        }
334
    }
335
}
336
337
// unassign all badges except the given one
338
//
339
function unassign_badges($is_user, $item, $badges, $k) {
340
    $list = null;
341
    for ($i=0; $i<count($badges); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

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

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

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Coding Style Performance introduced by
The use of count() 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...
342
        if ($i == $k) continue;
343
        $badge = $badges[$i];
344
        if ($list) {
345
            $list .= ",$badge->id";
346
        } else {
347
            $list = "$badge->id";
348
        }
349
    }
350
    if ($is_user) {
351
        BoincBadgeUser::delete("user_id=$item->id and badge_id in ($list)");
352
    } else {
353
        BoincBadgeTeam::delete("team_id=$item->id and badge_id in ($list)");
354
    }
355
}
356
357
////// end badge-related stuff
358
359
function running_from_web_server() {
360
    return array_key_exists("SERVER_PORT", $_SERVER);
361
}
362
363
if (isset($cli_only)) {
364
    if (running_from_web_server()) {
365
        die("This script is intended to be run from the command line,
366
            not from the web server."
367
        );
368
    }
369
}
370
371
if (!isset($skip_auth_ops) && array_key_exists("SERVER_PORT", $_SERVER)) {
372
    auth_ops();
373
}
374
375
// returns true when this is a readonly ops section
376
// currently a dummy because this needs to be ported from Einstein@home
377
//
378
function in_rops() {
379
    return false;
380
}
381
382
function cancel_wus_where($clause) {
383
    $q1 = "CREATE TEMPORARY TABLE tmp SELECT id FROM workunit WHERE $clause;";
384
    $q2 = "UPDATE result r INNER JOIN tmp t on r.workunitid=t.id SET server_state=5, outcome=5 WHERE server_state=2;";
385
    $q3 = "UPDATE workunit w INNER JOIN tmp t on w.id=t.id SET error_mask=error_mask|16, transition_time=0;";
386
    $q4 = "DROP TABLE tmp;";
387
388
    $db = BoincDb::get();
389
390
    if (!$db->do_query($q1)) {
391
        echo "MySQL command '$q1' failed:<br/>unable to create temporary WU id table.<br>\n";
392
        return 1;
393
    } else if (!$db->do_query($q2)) {
394
        echo "MySQL command '$q2' failed:<br/>unable to cancel unsent results.<br>\n";
395
        $db->do_query($q4);
396
        return 2;
397
    } else if (!$db->do_query($q3)) {
398
      echo "MySQL command '$q3' failed:<br/>unable to cancel workunits and trigger transitioner.<br>\n";
399
        $db->do_query($q4);
400
        return 3;
401
    }
402
    $db->do_query($q4);
403
    echo "Successfully canceled WUs WHERE '$clause'<br>\n";
404
    return 0;
405
}
406
407
?>
408