Passed
Push — dpa_buda13 ( 0241f6 )
by David
10:52
created

get_remote_app_names()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
// This file is part of BOINC.
4
// http://boinc.berkeley.edu
5
// Copyright (C) 2024 University of California
6
//
7
// BOINC is free software; you can redistribute it and/or modify it
8
// under the terms of the GNU Lesser General Public License
9
// as published by the Free Software Foundation,
10
// either version 3 of the License, or (at your option) any later version.
11
//
12
// BOINC is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
// See the GNU Lesser General Public License for more details.
16
//
17
// You should have received a copy of the GNU Lesser General Public License
18
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
19
20
// remote job submission functions.
21
//
22
// A 'remote app' is one where jobs are submitted remotely:
23
// - via web RPCs
24
// - (and possibly also) via forms on the project web site
25
//
26
// In both cases only users with permission can submit; either
27
// - a user_submit record with submit_all set
28
// - a user_submit_app record
29
//
30
// They are apps are described in $remote_apps in project.inc
31
//
32
// This page has several functions:
33
// - links to app-specific job-submission pages
34
// - Admin (if privileged user)
35
// - manage batches
36
//      view status, get output files, abort, retire
37
//   (this also shows batches created on the server)
38
// - set 'use only my computers'
39
40
require_once("../inc/submit_db.inc");
41
require_once("../inc/util.inc");
42
require_once("../inc/result.inc");
43
require_once("../inc/submit_util.inc");
44
require_once("../project/project.inc");
45
require_once('../project/remote_apps.inc');
46
47
display_errors();
48
49
define("PAGE_SIZE", 20);
50
51
function return_link() {
52
    echo "<p><a href=submit.php>Return to job submission page</a>\n";
53
}
54
55
// get params of in-progress batches; they might not be in progress anymore.
56
//
57
function get_batches_params($batches) {
58
    $b = [];
59
    foreach ($batches as $batch) {
60
        if ($batch->state == BATCH_STATE_IN_PROGRESS) {
61
            $wus = BoincWorkunit::enum("batch = $batch->id");
62
            $b[] = get_batch_params($batch, $wus);
63
        } else {
64
            $b[] = $batch;
65
        }
66
    }
67
    return $b;
68
}
69
70
function state_count($batches, $state) {
71
    $n = 0;
72
    foreach ($batches as $batch) {
73
        if ($batch->state == $state) $n++;
74
    }
75
    return $n;
76
}
77
78
function show_all_link($batches, $state, $limit, $user, $app) {
79
    $n = state_count($batches, $state);
80
    if ($n > $limit) {
81
        if ($user) $userid = $user->id;
82
        else $userid = 0;
83
        if ($app) $appid = $app->id;
84
        else $appid = 0;
85
86
        echo "Showing the most recent $limit of $n batches.
87
            <a href=submit.php?action=show_all&state=$state&userid=$userid&appid=$appid>Show all $n</a>
88
            <p>
89
        ";
90
    }
91
}
92
93
function show_in_progress($batches, $limit, $user, $app) {
94
    echo "<h3>Batches in progress</h3>\n";
95
    $first = true;
96
    $n = 0;
97
    foreach ($batches as $batch) {
98
        if ($batch->state != BATCH_STATE_IN_PROGRESS) continue;
99
        if ($limit && $n == $limit) break;
100
        $n++;
101
        if ($first) {
102
            $first = false;
103
            if ($limit) {
104
                show_all_link($batches, BATCH_STATE_IN_PROGRESS, $limit, $user, $app);
105
            }
106
            form_start('');     // for alignment
107
            start_table('table-striped');
108
            table_header(
109
                "Name",
110
                "ID",
111
                "User",
112
                "App",
113
                "# jobs",
114
                "Progress",
115
                "Submitted"
116
                //"Logical end time<br><small>Determines priority</small>"
117
            );
118
        }
119
        $pct_done = (int)($batch->fraction_done*100);
120
        table_row(
121
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
122
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
123
            $batch->user_name,
124
            $batch->app_name,
125
            $batch->njobs,
126
            "$pct_done%",
127
            local_time_str($batch->create_time)
128
            //local_time_str($batch->logical_end_time)
129
        );
130
    }
131
    if ($first) {
132
        echo "<p>None.\n";
133
    } else {
134
        end_table();
135
        form_end();
136
    }
137
}
138
139
function show_complete($batches, $limit, $user, $app) {
140
    $first = true;
141
    $n = 0;
142
    foreach ($batches as $batch) {
143
        if ($batch->state != BATCH_STATE_COMPLETE) continue;
144
        if ($limit && $n == $limit) break;
145
        $n++;
146
        if ($first) {
147
            $first = false;
148
            echo "<h3>Completed batches</h3>\n";
149
            if ($limit) {
150
                show_all_link($batches, BATCH_STATE_COMPLETE, $limit, $user, $app);
151
            }
152
            form_start('submit.php', 'get');
153
            form_input_hidden('action', 'retire_multi');
154
            start_table('table-striped');
155
            table_header(
156
                "Name", "ID", "User", "App", "# Jobs", "Submitted", "Select"
157
            );
158
        }
159
        table_row(
160
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
161
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
162
            $batch->user_name,
163
            $batch->app_name,
164
            $batch->njobs,
165
            local_time_str($batch->create_time),
166
            sprintf('<input type=checkbox name=retire_%d>', $batch->id)
167
        );
168
    }
169
    if ($first) {
170
        echo "<p>No completed batches.\n";
171
    } else {
172
        end_table();
173
        form_submit('Retire selected batches');
174
        form_end();
175
    }
176
}
177
178
function show_aborted($batches, $limit, $user, $app) {
179
    $first = true;
180
    $n = 0;
181
    foreach ($batches as $batch) {
182
        if ($batch->state != BATCH_STATE_ABORTED) continue;
183
        if ($limit && $n == $limit) break;
184
        $n++;
185
        if ($first) {
186
            $first = false;
187
            echo "<h2>Aborted batches</h2>\n";
188
            if ($limit) {
189
                show_all_link($batches, BATCH_STATE_ABORTED, $limit, $user, $app);
190
            }
191
            form_start('');
192
            start_table();
193
            table_header("name", "ID", "user", "app", "# jobs", "submitted");
194
        }
195
        table_row(
196
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
197
            "<a href=submit.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
198
            $batch->user_name,
199
            $batch->app_name,
200
            $batch->njobs,
201
            local_time_str($batch->create_time)
202
        );
203
    }
204
    if (!$first) {
205
        end_table();
206
        form_end();
207
    }
208
}
209
210
// fill in the app and user names in list of batches
211
// TODO: speed this up by making list of app and user IDs
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
212
// and doing lookup just once.
213
//
214
function fill_in_app_and_user_names(&$batches) {
215
    foreach ($batches as $batch) {
216
        $app = BoincApp::lookup_id($batch->app_id);
217
        if ($app) {
218
            $batch->app_name = $app->name;
219
            if ($batch->description) {
220
                $batch->app_name .= ": $batch->description";
221
            }
222
        } else {
223
            $batch->app_name = "unknown";
224
        }
225
        $user = BoincUser::lookup_id($batch->user_id);
226
        if ($user) {
227
            $batch->user_name = $user->name;
228
        } else {
229
            $batch->user_name = "missing user $batch->user_id";
230
        }
231
    }
232
}
233
234
// show a set of batches
235
//
236
function show_batches($batches, $limit, $user, $app) {
237
    fill_in_app_and_user_names($batches);
238
    $batches = get_batches_params($batches);
239
    show_in_progress($batches, $limit, $user, $app);
240
    show_complete($batches, $limit, $user, $app);
241
    show_aborted($batches, $limit, $user, $app);
242
}
243
244
// show links to per-app job submission forms
245
//
246
function handle_main($user) {
247
    global $remote_apps;
248
    $user_submit = BoincUserSubmit::lookup_userid($user->id);
249
    if (!$user_submit) {
250
        error_page("Ask the project admins for permission to submit jobs");
251
    }
252
253
    page_head("Submit jobs");
254
255
    // show links to per-app job submission pages
256
    //
257
    foreach ($remote_apps as $area => $apps) {
258
        panel($area,
259
            function() use ($apps) {
260
                foreach ($apps as $app) {
261
                    if (empty($app->form)) continue;
262
                    // show app logo if available
263
                    if (!empty($app->logo)) {
264
                        echo sprintf(
265
                            '<a href=%s><img width=100 src=%s></a>&nbsp;',
266
                            $app->form, $app->logo
267
                        );
268
                    } else {
269
                        echo sprintf(
270
                            '<li><a href=%s>%s</a><p>',
271
                            $app->form, $app->long_name
272
                        );
273
                    }
274
                }
275
            }
276
        );
277
    }
278
279
    form_start('submit.php');
280
    form_input_hidden('action', 'update_only_own');
281
    form_radio_buttons(
282
        'Jobs you submit can run', 'only_own',
283
        [
284
            [0, 'on any computer'],
285
            [1, 'only on your computers']
0 ignored issues
show
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
286
        ],
287
        $user->seti_id
288
    );
289
    form_submit('Update');
290
    form_end();
291
    page_tail();
292
}
293
294
function handle_show_status($user) {
295
    page_head("Job status");
296
    $batches = BoincBatch::enum("user_id = $user->id order by id desc");
297
    get_batches_params($batches);
298
    show_batches($batches, PAGE_SIZE, $user, null);
299
300
    page_tail();
301
}
302
303
function handle_update_only_own($user) {
304
    $val = get_int('only_own');
305
    $user->update("seti_id=$val");
306
    header("Location: submit.php");
307
}
308
309
// get list of app names of remote apps
310
//
311
function get_remote_app_names() {
312
    global $remote_apps;
313
    $x = [];
314
    foreach ($remote_apps as $category => $apps) {
315
        foreach ($apps as $app) {
316
            $x[] = $app->app_name;
317
        }
318
    }
319
    return array_unique($x);
320
}
321
322
// show links for everything the user has admin access to
323
//
324
function handle_admin($user) {
325
    $user_submit = BoincUserSubmit::lookup_userid($user->id);
326
    if (!$user_submit) error_page('no access');
327
    page_head("Administer job submission");
328
    if ($user_submit->manage_all) {
329
        // user can administer all apps
330
        //
331
        echo "<li>All applications<br>
332
            <ul>
333
            <li> <a href=submit.php?action=admin_all>View all batches</a>
334
            <li> <a href=manage_project.php>Manage user permissions</a>
335
            </ul>
336
        ";
337
        $app_names = get_remote_app_names();
338
        foreach ($app_names as $app_name) {
339
            $app_name = BoincDb::escape_string($app_name);
340
            $app = BoincApp::lookup("name='$app_name'");
341
            echo "
342
                <li>$app->user_friendly_name<br>
343
                <ul>
344
                <li><a href=submit.php?action=admin_app&app_id=$app->id>View batches</a>
345
                <li> <a href=manage_app.php?app_id=$app->id&amp;action=app_version_form>Manage app versions</a>
346
                <li> <a href=manage_app.php?app_id=$app->id&amp;action=permissions_form>Manage user permissions</a>
347
                <li> <a href=manage_app.php?app_id=$app->id&amp;action=batches_form>Manage batches</a>
348
                </ul>
349
            ";
350
        }
351
    } else {
352
        // see if user can administer specific apps
353
        //
354
        $usas = BoincUserSubmitApp::enum("user_id=$user->id");
355
        foreach ($usas as $usa) {
356
            $app = BoincApp::lookup_id($usa->app_id);
357
            echo "<li>$app->user_friendly_name<br>
358
                <a href=submit.php?action=admin_app&app_id=$app->id>Batches</a>
359
            ";
360
            if ($usa->manage) {
361
                echo "&middot;
362
                    <a href=manage_app.php?app_id=$app->id&action=app_version_form>Versions</a>
363
                ";
364
            }
365
        }
366
    }
367
    echo "</ul>\n";
368
    page_tail();
369
}
370
371
function handle_admin_app($user) {
372
    $app_id = get_int("app_id");
373
    $app = BoincApp::lookup_id($app_id);
374
    if (!$app) error_page("no such app");
375
    if (!has_admin_access($user, $app_id)) {
376
        error_page('no access');
377
    }
378
379
    page_head("Administer batches for $app->user_friendly_name");
380
    $batches = BoincBatch::enum("app_id = $app_id order by id desc");
381
    show_batches($batches, PAGE_SIZE, null, $app);
382
    page_tail();
383
}
384
function handle_admin_all($user) {
385
    page_head("Administer batches (all apps)");
386
    $batches = BoincBatch::enum("true order by id desc");
387
    show_batches($batches, PAGE_SIZE, null, null);
388
    page_tail();
389
}
390
391
392
// show the statics of mem/disk usage of jobs in a batch
393
//
394
function handle_batch_stats($user) {
395
    $batch_id = get_int('batch_id');
396
    $batch = BoincBatch::lookup_id($batch_id);
397
    $results = BoincResult::enum("batch = $batch->id");
398
    page_head("Statistics for batch $batch_id");
399
    $n = 0;
400
    $wss_sum = 0;
401
    $swap_sum = 0;
402
    $disk_sum = 0;
403
    $wss_max = 0;
404
    $swap_max = 0;
405
    $disk_max = 0;
406
    foreach ($results as $r) {
407
        if ($r->outcome != RESULT_OUTCOME_SUCCESS) {
408
            continue;
409
        }
410
        // pre-7.3.16 clients don't report usage info
411
        //
412
        if ($r->peak_working_set_size == 0) {
413
            continue;
414
        }
415
        $n++;
416
        $wss_sum += $r->peak_working_set_size;
417
        if ($r->peak_working_set_size > $wss_max) {
418
            $wss_max = $r->peak_working_set_size;
419
        }
420
        $swap_sum += $r->peak_swap_size;
421
        if ($r->peak_swap_size > $swap_max) {
422
            $swap_max = $r->peak_swap_size;
423
        }
424
        $disk_sum += $r->peak_disk_usage;
425
        if ($r->peak_disk_usage > $disk_max) {
426
            $disk_max = $r->peak_disk_usage;
427
        }
428
    }
429
    if ($n == 0) {
430
        echo "No qualifying results.";
431
        page_tail();
432
        return;
433
    }
434
    text_start(800);
435
    start_table('table-striped');
436
    row2("qualifying results", $n);
437
    row2("mean WSS", size_string($wss_sum/$n));
438
    row2("max WSS", size_string($wss_max));
439
    row2("mean swap", size_string($swap_sum/$n));
440
    row2("max swap", size_string($swap_max));
441
    row2("mean disk usage", size_string($disk_sum/$n));
442
    row2("max disk usage", size_string($disk_max));
443
    end_table();
444
    text_end();
445
    page_tail();
446
}
447
448
// return HTML for a color-coded batch progress bar
449
// green: successfully completed jobs
450
// red: failed
451
// light green: in progress
452
// light gray: unsent
453
//
454
function progress_bar($batch, $wus, $width) {
455
    $nsuccess = $batch->njobs_success;
456
    $nerror = $batch->nerror_jobs;
457
    $nin_prog = $batch->njobs_in_prog;
458
    $nunsent = $batch->njobs - $nsuccess - $nerror - $nin_prog;
459
    $w_success = $width*$nsuccess/$batch->njobs;
460
    $w_fail = $width*$nerror/$batch->njobs;
461
    $w_prog = $width*$nin_prog/$batch->njobs;
462
    $w_unsent = $width*$nunsent/$batch->njobs;
463
    $x = '<table height=20><tr>';
464
    if ($w_fail) {
465
        $x .= "<td width=$w_fail bgcolor=red></td>";
466
    }
467
    if ($w_success) {
468
        $x .= "<td width=$w_success bgcolor=green></td>";
469
    }
470
    if ($w_prog) {
471
        $x .= "<td width=$w_prog bgcolor=lightgreen></td>";
472
    }
473
    if ($w_unsent) {
474
        $x .= "<td width=$w_unsent bgcolor=gray></td>";
475
    }
476
    $x .= "</tr></table>
477
        <strong>
478
        <font color=red>$nerror failed</font> &middot;
479
        <font color=green>$nsuccess completed</font> &middot;
480
        <font color=lightgreen>$nin_prog in progress</font> &middot;
481
        <font color=gray>$nunsent unsent</font>
482
        </strong>
483
    ";
484
    return $x;
485
}
486
487
// show the details of an existing batch
488
//
489
function handle_query_batch($user) {
490
    $batch_id = get_int('batch_id');
491
    $batch = BoincBatch::lookup_id($batch_id);
492
    $app = BoincApp::lookup_id($batch->app_id);
493
    $wus = BoincWorkunit::enum("batch = $batch->id");
494
    $batch = get_batch_params($batch, $wus);
495
    if ($batch->user_id == $user->id) {
496
        $owner = $user;
497
    } else {
498
        $owner = BoincUser::lookup_id($batch->user_id);
499
    }
500
501
    $is_assim_move = is_assim_move($app);
502
503
    page_head("Batch $batch_id");
504
    text_start(800);
505
    start_table();
506
    row2("name", $batch->name);
507
    if ($batch->description) {
508
        row2('description', $batch->description);
509
    }
510
    if ($owner) {
511
        row2('submitter', $owner->name);
512
    }
513
    row2("application", $app?$app->name:'---');
514
    row2("state", batch_state_string($batch->state));
515
    //row2("# jobs", $batch->njobs);
516
    //row2("# error jobs", $batch->nerror_jobs);
517
    //row2("logical end time", time_str($batch->logical_end_time));
518
    if ($batch->expire_time) {
519
        row2("expiration time", time_str($batch->expire_time));
520
    }
521
    if ($batch->njobs) {
522
        row2("progress", progress_bar($batch, $wus, 600));
523
    }
524
    if ($batch->completion_time) {
525
        row2("completed", local_time_str($batch->completion_time));
526
    }
527
    row2("GFLOP/hours, estimated", number_format(credit_to_gflop_hours($batch->credit_estimate), 2));
528
    row2("GFLOP/hours, actual", number_format(credit_to_gflop_hours($batch->credit_canonical), 2));
529
    if (!$is_assim_move) {
530
        row2("Total size of output files",
531
            size_string(batch_output_file_size($batch->id))
532
        );
533
    }
534
    end_table();
535
    echo "<p>";
536
537
    if ($is_assim_move) {
538
        $url = "get_output3.php?action=get_batch&batch_id=$batch->id";
539
    } else {
540
        $url = "get_output2.php?cmd=batch&batch_id=$batch->id";
541
    }
542
    echo "<p>";
543
    show_button($url, "Get zipped output files");
544
    echo "<p>";
545
    switch ($batch->state) {
546
    case BATCH_STATE_IN_PROGRESS:
547
        show_button(
548
            "submit.php?action=abort_batch&batch_id=$batch_id",
549
            "Abort batch"
550
        );
551
        break;
552
    case BATCH_STATE_COMPLETE:
553
    case BATCH_STATE_ABORTED:
554
        show_button(
555
            "submit.php?action=retire_batch&batch_id=$batch_id",
556
            "Retire batch"
557
        );
558
        break;
559
    }
560
    echo "<p>";
561
    show_button("submit.php?action=batch_stats&batch_id=$batch_id",
562
        "Show memory/disk usage statistics"
563
    );
564
565
    echo "<h2>Jobs</h2>\n";
566
    start_table();
567
    $x = [
568
        "Name <br><small>click for details</small>",
569
        "status"
0 ignored issues
show
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
570
    ];
571
    row_heading_array($x);
572
    foreach($wus as $wu) {
573
        $y = '';
574
        switch($wu->status) {
575
        case WU_SUCCESS:
576
            $resultid = $wu->canonical_resultid;
577
            $y = '<font color="green">completed</font>';
578
            break;
579
        case WU_ERROR:
580
            $y = '<font color="red">failed</font>';
581
            break;
582
        case WU_IN_PROGRESS:
583
            $y = '<font color="lightgreen">in progress</font>';
584
            break;
585
        case WU_UNSENT:
586
            $y = '<font color="gray">unsent</font>';
587
            break;
588
        }
589
        $x = [
590
            "<a href=submit.php?action=query_job&wuid=$wu->id>$wu->name</a>",
591
            $y,
592
        ];
593
        row_array($x);
594
    }
595
    end_table();
596
    return_link();
597
    text_end();
598
    page_tail();
599
}
600
601
// Does the assimilator for the given app move output files
602
// to a results/<batchid>/ directory?
603
// This info is stored in the $remote_apps data structure in project.inc
604
//
605
function is_assim_move($app) {
606
    global $remote_apps;
607
    foreach ($remote_apps as $category => $apps) {
608
        foreach ($apps as $web_app) {
609
            if ($web_app->app_name == $app->name) {
610
                return $web_app->is_assim_move;
611
            }
612
        }
613
    }
614
    return false;
615
}
616
617
// show the details of a job, including links to see the output files
618
//
619
function handle_query_job($user) {
620
    $wuid = get_int('wuid');
621
    $wu = BoincWorkunit::lookup_id($wuid);
622
    if (!$wu) error_page("no such job");
623
624
    $app = BoincApp::lookup_id($wu->appid);
625
    $is_assim_move = is_assim_move($app);
626
627
    page_head("Job '$wu->name'");
628
    text_start(800);
629
630
    echo "
631
        <li><a href=workunit.php?wuid=$wuid>Workunit details</a>
632
        <p>
633
        <li><a href=submit.php?action=query_batch&batch_id=$wu->batch>Batch details</a>
634
    ";
635
636
    echo "<h2>Job instances</h2>\n";
637
    start_table('table-striped');
638
    table_header(
639
        "ID<br><small>click for details and stderr</small>",
640
        "State",
641
        "Output files"
642
    );
643
    $results = BoincResult::enum("workunitid=$wuid");
644
    $upload_dir = parse_config(get_config(), "<upload_dir>");
645
    $fanout = parse_config(get_config(), "<uldl_dir_fanout>");
646
    foreach($results as $result) {
647
        $x = [
648
            "<a href=result.php?resultid=$result->id>$result->id</a>",
649
            state_string($result)
0 ignored issues
show
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
650
        ];
651
        $i = 0;
652
        if ($result->server_state == RESULT_SERVER_STATE_OVER) {
653
            $phys_names = get_outfile_phys_names($result);
654
            $log_names = get_outfile_log_names($result);
655
            for ($i=0; $i<count($phys_names); $i++) {
0 ignored issues
show
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...
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...
656
                if ($is_assim_move) {
657
                    // file is in
658
                    // project/results/<batchid>/<wu_name>__file_<log_name>
659
                    $path = sprintf('results/%s/%s__file_%s',
660
                        $wu->batch, $wu->name, $log_names[$i]
661
                    );
662
                    $x[] = "<a href=get_output3.php?action=get_file&path=$path>view</a> &middot; <a href=get_output3.php?action=get_file&path=$path&download=1>download</a>";
663
                } else {
664
                    $path = dir_hier_path(
665
                        $phys_names[$i], $upload_dir, $fanout
666
                    );
667
                    if (file_exists($path)) {
668
                        $url = sprintf(
669
                            'get_output2.php?cmd=result&result_id=%d&file_num=%d',
670
                            $result->id, $i
671
                        );
672
                        $s = stat($path);
673
                        $size = $s['size'];
674
                        $x[] = sprintf('<a href=%s>%s</a> (%s bytes)<br/>',
675
                            $url,
676
                            $log_names[$i],
677
                            number_format($size)
678
                        );
679
                    } else {
680
                        $x[] = sprintf("file '%s' is missing", $log_names[$i]);
681
                    }
682
                }
683
            }
684
        } else {
685
            $x[] = '---';
686
        }
687
        row_array($x);
688
    }
689
    end_table();
690
691
    // show input files
692
    //
693
    echo "<h2>Input files</h2>\n";
694
    $x = "<in>".$wu->xml_doc."</in>";
695
    $x = simplexml_load_string($x);
696
    start_table('table-striped');
697
    table_header("Name<br><small>(click to view)</small>", "Size (bytes)");
698
    foreach ($x->workunit->file_ref as $fr) {
699
        $pname = (string)$fr->file_name;
700
        $lname = (string)$fr->open_name;
701
        foreach ($x->file_info as $fi) {
702
            if ((string)$fi->name == $pname) {
703
                table_row(
704
                    "<a href=$fi->url>$lname</a>",
705
                    $fi->nbytes
706
                );
707
                break;
708
            }
709
        }
710
    }
711
712
    end_table();
713
    text_end();
714
    return_link();
715
    page_tail();
716
}
717
718
// is user allowed to retire or abort this batch?
719
//
720
function check_access($user, $batch) {
721
    if ($user->id == $batch->user_id) return;
722
    $user_submit = BoincUserSubmit::lookup_userid($user->id);
723
    if ($user_submit->manage_all) return;
724
    $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$batch->app_id");
725
    if ($usa->manage) return;
726
    error_page("no access");
727
}
728
729
function handle_abort_batch() {
730
    $batch_id = get_int('batch_id');
731
    $batch = BoincBatch::lookup_id($batch_id);
732
    if (!$batch) error_page("no such batch");
733
    check_access($user, $batch);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user seems to be never defined.
Loading history...
734
735
    if (get_int('confirmed', true)) {
736
        abort_batch($batch);
737
        page_head("Batch aborted");
738
        return_link();
739
        page_tail();
740
    } else {
741
        page_head("Confirm abort batch");
742
        echo "
743
            Aborting a batch will cancel all unstarted jobs.
744
            Are you sure you want to do this?
745
            <p>
746
        ";
747
        show_button(
748
            "submit.php?action=abort_batch&batch_id=$batch_id&confirmed=1",
749
            "Yes - abort batch"
750
        );
751
        return_link();
752
        page_tail();
753
    }
754
}
755
756
function handle_retire_batch($user) {
757
    $batch_id = get_int('batch_id');
758
    $batch = BoincBatch::lookup_id($batch_id);
759
    if (!$batch) error_page("no such batch");
760
    check_access($user, $batch);
761
762
    if (get_int('confirmed', true)) {
763
        retire_batch($batch);
764
        page_head("Batch retired");
765
        return_link();
766
        page_tail();
767
    } else {
768
        page_head("Confirm retire batch");
769
        echo "
770
            Retiring a batch will remove all of its output files.
771
            Are you sure you want to do this?
772
            <p>
773
        ";
774
        show_button(
775
            "submit.php?action=retire_batch&batch_id=$batch_id&confirmed=1",
776
            "Yes - retire batch"
777
        );
778
        return_link();
779
        page_tail();
780
    }
781
}
782
783
function handle_retire_multi($user) {
784
    $batches = BoincBatch::enum(
785
        sprintf('user_id=%d and state=%d', $user->id, BATCH_STATE_COMPLETE)
786
    );
787
    page_head('Retiring batches');
788
    foreach ($batches as $batch) {
789
        $x = sprintf('retire_%d', $batch->id);
790
        if (get_str($x, true) == 'on') {
791
            retire_batch($batch);
792
            echo "<p>retired batch $batch->name\n";
793
        }
794
    }
795
    return_link();
796
    page_tail();
797
}
798
799
function show_batches_in_state($batches, $state) {
800
    switch ($state) {
801
    case BATCH_STATE_IN_PROGRESS:
802
        page_head("Batches in progress");
803
        show_in_progress($batches, 0, null, null);
804
        break;
805
    case BATCH_STATE_COMPLETE:
806
        page_head("Completed batches");
807
        show_complete($batches, 0, null, null);
808
        break;
809
    case BATCH_STATE_ABORTED:
810
        page_head("Aborted batches");
811
        show_aborted($batches, 0, null, null);
812
        break;
813
    }
814
    page_tail();
815
}
816
817
function handle_show_all($user) {
818
    $userid = get_int("userid");
819
    $appid = get_int("appid");
820
    $state = get_int("state");
821
    if ($userid) {
822
        // user looking at their own batches
823
        //
824
        if ($userid != $user->id) error_page("wrong user");
825
        $batches = BoincBatch::enum("user_id = $user->id and state=$state order by id desc");
826
        fill_in_app_and_user_names($batches);
827
        show_batches_in_state($batches, $state);
828
    } else {
829
        // admin looking at batches
830
        //
831
        if (!has_admin_access($user, $appid)) {
832
            error_page('no access');
833
        }
834
        if ($appid) {
835
            $app = BoincApp::lookup_id($appid);
836
            if (!$app) error_page("no such app");
837
            $batches = BoincBatch::enum("app_id = $appid and state=$state order by id desc");
838
        } else {
839
            $batches = BoincBatch::enum("state=$state order by id desc");
840
        }
841
        fill_in_app_and_user_names($batches);
842
        show_batches_in_state($batches, $state);
843
    }
844
}
845
846
$user = get_logged_in_user();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $user is correct as get_logged_in_user() 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...
847
848
$action = get_str('action', true);
849
850
switch ($action) {
851
case '': handle_main($user); break;
852
case 'abort_batch': handle_abort_batch($user); break;
0 ignored issues
show
Unused Code introduced by
The call to handle_abort_batch() has too many arguments starting with $user. ( Ignorable by Annotation )

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

852
case 'abort_batch': /** @scrutinizer ignore-call */ handle_abort_batch($user); break;

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
853
case 'admin': handle_admin($user); break;
854
case 'admin_app': handle_admin_app($user); break;
855
case 'admin_all': handle_admin_all($user); break;
856
case 'batch_stats': handle_batch_stats($user); break;
857
case 'query_batch': handle_query_batch($user); break;
858
case 'query_job': handle_query_job($user); break;
859
case 'retire_batch': handle_retire_batch($user); break;
860
case 'retire_multi': handle_retire_multi($user); break;
861
case 'show_all': handle_show_all($user); break;
862
case 'status': handle_show_status($user); break;
863
case 'update_only_own': handle_update_only_own($user); break;
864
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
DEFAULT case must have a breaking statement
Loading history...
865
    error_page("no such action $action");
866
}
867
868
?>
869