Issues (1963)

html/user/submit_example.php (11 issues)

1
<?php
2
3
// This file is part of BOINC.
4
// http://boinc.berkeley.edu
5
// Copyright (C) 2011 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
// example of a web interface to remote job submission
21
//
22
// Although the architecture is intended to support remote portals,
23
// this example must run on the BOINC project server.
24
// In particular:
25
// - It assumes cookie-based authentication,
26
//   as is done by the BOINC code.
27
//   You'll need to adapt/extend this considerably to run this
28
//   on a server other than the BOINC project server.
29
// - It uses some functions from BOINC (page_head() etc.).
30
//   When you adapt this to your own purposes,
31
//   you can strip out this stuff if the web site doesn't use BOINC
32
33
// THIS IS PRETTY MUCH USELESS
34
35
require_once("../inc/submit.inc");
36
require_once("../inc/common_defs.inc");
37
require_once("../inc/submit_db.inc");
38
require_once("../inc/submit_util.inc");
39
    // needed for access control stuff
40
require_once("../inc/util.inc");
41
require_once("../project/project.inc");
42
43
display_errors();
44
45
// hardwired app name for now
46
define('APP_NAME', 'remote_test');
47
48
$project = master_url();
49
$user = get_logged_in_user();
0 ignored issues
show
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...
50
$auth = $user->authenticator;
51
52
// the job submission "home page":
53
// show the user's in-progress and completed batches,
54
// and a button for creating a new batch
55
//
56
function handle_main() {
57
    global $project, $auth;
58
    $req = new StdClass;
59
    $req->project = $project;
60
    $req->authenticator = $auth;
61
    list($batches, $errmsg) = boinc_query_batches($req);
62
    if ($errmsg) error_page(htmlentities($errmsg));
63
64
    page_head("Job submission and control");
65
66
    echo "
67
        This is an example of a web interface
68
        for remote submission of BOINC jobs.
69
        It lets you
70
        <ul>
71
        <li> Upload files
72
        <li> submit batches of jobs,
73
        <li> see the status of in-progress and completed batches.
74
        </ul>
75
        <p>
76
        To use this, you must be logged in as a user
77
        with permission to submit jobs.
78
        <p>
79
    ";
80
    show_button("submit_example.php?action=create_form", "Create new batch");
81
82
    $first = true;
83
    foreach ($batches as $batch) {
84
        if ($batch->state != BATCH_STATE_IN_PROGRESS) continue;
85
        if ($first) {
86
            $first = false;
87
            echo "<h2>Batches in progress</h2>\n";
88
            start_table();
89
            table_header("name", "ID", "app", "# jobs", "progress", "submitted");
90
        }
91
        $pct_done = (int)($batch->fraction_done*100);
92
        table_row(
93
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
94
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
95
            $batch->app_name,
96
            $batch->njobs,
97
            "$pct_done%",
98
            local_time_str($batch->create_time)
99
        );
100
    }
101
    if ($first) {
102
        echo "<p>You have no in-progress batches.\n";
103
    } else {
104
        end_table();
105
    }
106
107
    $first = true;
108
    foreach ($batches as $batch) {
109
        if ($batch->state != BATCH_STATE_COMPLETE) continue;
110
        if ($first) {
111
            $first = false;
112
            echo "<h2>Completed batches</h2>\n";
113
            start_table();
114
            table_header("name", "ID", "# jobs", "submitted");
115
        }
116
        table_row(
117
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
118
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
119
            $batch->njobs,
120
            local_time_str($batch->create_time)
121
        );
122
    }
123
    if ($first) {
124
        echo "<p>You have no completed batches.\n";
125
    } else {
126
        end_table();
127
    }
128
129
    $first = true;
130
    foreach ($batches as $batch) {
131
        if ($batch->state != BATCH_STATE_ABORTED) continue;
132
        if ($first) {
133
            $first = false;
134
            echo "<h2>Aborted batches</h2>\n";
135
            start_table();
136
            table_header("name", "ID", "# jobs", "submitted");
137
        }
138
        table_row(
139
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>",
140
            "<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>",
141
            $batch->njobs,
142
            local_time_str($batch->create_time)
143
        );
144
    }
145
    if (!$first) {
146
        end_table();
147
    }
148
149
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
150
    page_tail();
151
}
152
153
// return an array of the apps this user is allowed to submit jobs for
154
//
155
function eligible_apps() {
156
    global $user;
157
    $apps = BoincApp::enum("deprecated = 0");
158
    $user_submit = BoincUserSubmit::lookup_userid($user->id);
159
    if (!$user_submit) return null;
160
    $a = array();
161
    foreach($apps as $app) {
162
        if ($user_submit->submit_all) {
163
            $a[] = $app;
164
        } else {
165
            if (BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id")) {
166
                $a[] = $app;
167
            }
168
        }
169
    }
170
    return $a;
171
}
172
173
// return HTML for a popup menu of apps
174
//
175
function app_select($apps) {
176
    $x = '<select class="form-control" name="app_name">\n';
177
    foreach ($apps as $app) {
178
        $x .= "<option value=$app->name>$app->user_friendly_name</option>\n";
179
    }
180
    $x .= "</select>\n";
181
    return $x;
182
}
183
184
// show a form for creating a batch.
185
//
186
function handle_create_form() {
187
    global $project, $auth;
188
189
    $apps = eligible_apps();
190
    if (!$apps) error_page("You are not allowed to submit jobs");
191
    page_head("Create batch");
192
    echo "
193
        This form lets you specify a batch of jobs,
194
        and either submit it or get and estimate of its completion time.
195
        <p>
196
        The job runs an application that
197
        <ul>
198
        <li> Reads an input file, converts it to upper case,
199
          and writes this to an output file.
200
            You give a URL from which this file can be read.
201
        <li> Takes a command-line parameter, and uses that
202
          number of seconds of CPU time
203
        You can specify a range of values for the parameter;
204
        this determines the number of jobs in the batch.
205
        </ul>
206
207
        <p>
208
        <form action=submit_example.php>
209
        <input type=hidden name=action value=create_action>
210
    ";
211
    start_table();
212
    row2("Batch name", "<input name=batch_name value=\"enter name\">");
213
//    row2("Application", app_select($apps));
214
    row2("Input file URL", "<input name=input_url size=60 value=\"https://google.com/\">");
215
    row2("Parameter low value (0..60)", "<input name=param_lo value=10>");
216
    row2("Parameter high value (0..60)", "<input name=param_hi value=20>");
217
    row2("Parameter increment (>= 1)", "<input name=param_inc value=1>");
218
    row2("",
219
        "<input class=\"btn btn-default\" type=submit name=get_estimate value=\"Get completion time estimate\">"
220
    );
221
    row2("",
222
        "<input class=\"btn btn-primary\" type=submit name=submit value=Submit>"
223
    );
224
    end_table();
225
    echo "</form>\n";
226
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
227
    page_tail();
228
}
229
230
// build a request object for boinc_*_batch() from form variables
231
//
232
function form_to_request() {
233
    global $project, $auth;
234
235
    $input_url = get_str('input_url');
236
    if (!$input_url) error_page("missing input URL");
237
    $param_lo = (double)get_str('param_lo');
238
    if ($param_lo<0 || $param_lo>60) error_page("param lo must be in 0..60");
239
    $param_hi = (double)get_str('param_hi');
240
    if ($param_hi<0 || $param_hi>60 || $param_hi <= $param_lo) {
241
        error_page("param hi must be in 0..60 and > param lo");
242
    }
243
    $param_inc = (double)get_str('param_inc');
244
    if ($param_inc < 1) error_page("param inc must be >= 1");
245
246
    $req = new StdClass;
247
    $req->project = $project;
248
    $req->authenticator = $auth;
249
    $req->app_name = APP_NAME;
250
    $req->batch_name = get_str('batch_name');
251
    $req->jobs = array();
252
253
    $f = new StdClass;
254
    $f->source = $input_url;
255
    $f->mode = 'semilocal';
256
257
    for ($x=$param_lo; $x<$param_hi; $x += $param_inc) {
258
        $job = new StdClass;
259
        $job->rsc_fpops_est = $x*1e9;
260
        $job->command_line = "--t $x";
261
        $job->input_files = array($f);
262
        $req->jobs[] = $job;
263
    }
264
265
    return $req;
266
}
267
268
// create and submit a batch
269
//
270
function handle_create_action() {
271
    global $project, $auth;
272
273
    $get_estimate = get_str('get_estimate', true);
274
    if ($get_estimate) {
275
        $req = form_to_request($project, $auth);
0 ignored issues
show
The call to form_to_request() has too many arguments starting with $project. ( Ignorable by Annotation )

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

275
        $req = /** @scrutinizer ignore-call */ form_to_request($project, $auth);

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...
276
        list($e, $errmsg) = boinc_estimate_batch($req);
277
        if ($errmsg) error_page(htmlentities($errmsg));
278
        page_head("Batch estimate");
279
        echo sprintf("Estimate: %.0f seconds", $e);
280
        echo "<p><a href=submit_example.php>Return to job control page</a>\n";
281
        page_tail();
282
    } else {
283
        $req = form_to_request($project, $auth);
284
        list($id, $errmsg) = boinc_submit_batch($req);
285
        if ($errmsg) error_page(htmlentities($errmsg));
286
        page_head("Batch submitted");
287
        echo "Batch created, ID: $id\n";
288
        echo "<p><a href=submit_example.php>Return to job control page</a>\n";
289
        page_tail();
290
    }
291
}
292
293
// show the details of an existing batch
294
//
295
function handle_query_batch() {
296
    global $project, $auth;
297
    $req = (object)array(
298
        'project' => $project,
299
        'authenticator' => $auth,
300
        'batch_id' => get_int('batch_id'),
301
    );
302
    list($batch, $errmsg) = boinc_query_batch($req);
303
    if ($errmsg) error_page(htmlentities($errmsg));
304
305
    page_head("Batch $req->batch_id");
306
    start_table();
307
    row2("name", $batch->name);
308
    row2("application", $batch->app_name);
309
    row2("state", batch_state_string($batch->state));
310
    row2("# jobs", $batch->njobs);
311
    row2("# error jobs", $batch->nerror_jobs);
312
    row2("progress", sprintf("%.0f%%", $batch->fraction_done*100));
313
    if ($batch->completion_time) {
314
        row2("completed", local_time_str($batch->completion_time));
315
    }
316
    row2("GFLOP/hours, estimated", number_format(credit_to_gflop_hours($batch->credit_estimate), 2));
317
    row2("GFLOP/hours, actual", number_format(credit_to_gflop_hours($batch->credit_canonical), 2));
318
    end_table();
319
    echo "<p>";
320
    $url = boinc_get_output_files($req);
321
    show_button($url, "Get zipped output files");
322
    echo "<p>";
323
    switch ($batch->state) {
324
    case BATCH_STATE_IN_PROGRESS:
325
        show_button(
326
            "submit_example.php?action=abort_batch_confirm&batch_id=$req->batch_id",
327
            "Abort batch"
328
        );
329
        break;
330
    case BATCH_STATE_COMPLETE:
331
    case BATCH_STATE_ABORTED:
332
        show_button(
333
            "submit_example.php?action=retire_batch_confirm&batch_id=$req->batch_id",
334
            "Retire batch"
335
        );
336
        break;
337
    }
338
339
    echo "<h2>Jobs</h2>\n";
340
    start_table();
341
    table_header(
342
        "Job ID<br><p class=\"text-muted\">click for details or to get output files</p>",
343
        "status",
344
        "Canonical instance<br><p class=\"text-muted\">click to see result page on BOINC server</p>"
345
    );
346
    foreach($batch->jobs as $job) {
347
        $id = (int)$job->id;
348
        $resultid = (int)$job->canonical_instance_id;
349
        if ($resultid) {
350
            $x = "<a href=result.php?resultid=$resultid>$resultid</a>";
351
            $y = "completed";
352
        } else {
353
            $x = "---";
354
            $y = "in progress";
355
        }
356
357
        echo "<tr>
358
                <td><a href=submit_example.php?action=query_job&job_id=$id>$id</a></td>
359
                <td>$y</td>
360
                <td>$x</td>
361
            </tr>
362
        ";
363
    }
364
    end_table();
365
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
366
    page_tail();
367
}
368
369
// show the details of a job, including links to see the output files
370
//
371
function handle_query_job() {
372
    global $project, $auth;
373
    $req = new StdClass;
374
    $req->project = $project;
375
    $req->authenticator = $auth;
376
    $req->job_id = get_int('job_id');
377
378
    list($reply, $errmsg) = boinc_query_job($req);
379
    if ($errmsg) error_page(htmlentities($errmsg));
380
381
    page_head("Job $req->job_id");
382
    echo "<a href=$project/workunit.php?wuid=$req->job_id>View workunit page on BOINC server</a>\n";
383
    echo "<h2>Instances</h2>\n";
384
    start_table();
385
    table_header(
386
        "Instance ID<br><p class=\"text-muted\">click for result page on BOINC server</p>",
387
        "State", "Output files"
388
    );
389
    foreach($reply->instances as $inst) {
390
        echo "<tr>
391
            <td><a href=result.php?resultid=$inst->id>$inst->id</a></td>
392
            <td>$inst->state</td>
393
            <td>
394
";
395
        $i = 0;
396
        foreach ($inst->outfiles as $outfile) {
397
            $req->instance_name = $inst->name;
398
            $req->file_num = $i;
399
            $url = boinc_get_output_file($req);
400
            echo "<a href=$url>$outfile->size bytes</a>";
401
            $i++;
402
        }
403
        echo "</td></tr>\n";
404
    }
405
    end_table();
406
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
407
    page_tail();
408
}
409
410
function handle_abort_batch_confirm() {
411
    $batch_id = get_int('batch_id');
412
    page_head("Confirm abort batch");
413
    echo "
414
        Aborting a batch will cancel all unstarted jobs.
415
        Are you sure you want to do this?
416
        <p>
417
    ";
418
    show_button(
419
        "submit_example.php?action=abort_batch&batch_id=$batch_id",
420
        "Yes - abort batch"
421
    );
422
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
423
    page_tail();
424
}
425
426
function handle_abort_batch() {
427
    global $project, $auth;
428
    $req->project = $project;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $req seems to be never defined.
Loading history...
429
    $req->authenticator = $auth;
430
    $req->batch_id = get_int('batch_id');
431
    $errmsg = boinc_abort_batch($req);
432
    if ($errmsg) error_page(htmlentities($errmsg));
433
    page_head("Batch aborted");
434
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
435
    page_tail();
436
}
437
438
function handle_retire_batch_confirm() {
439
    $batch_id = get_int('batch_id');
440
    page_head("Confirm retire batch");
441
    echo "
442
        Retiring a batch will remove all of its output files.
443
        Are you sure you want to do this?
444
        <p>
445
    ";
446
    show_button(
447
        "submit_example.php?action=retire_batch&batch_id=$batch_id",
448
        "Yes - retire batch"
449
    );
450
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
451
    page_tail();
452
}
453
454
function handle_retire_batch() {
455
    global $project, $auth;
456
    $req->project = $project;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $req seems to be never defined.
Loading history...
457
    $req->authenticator = $auth;
458
    $req->batch_id = get_int('batch_id');
459
    $errmsg = boinc_retire_batch($req);
460
    if ($errmsg) error_page(htmlentities($errmsg));
461
    page_head("Batch retired");
462
    echo "<p><a href=submit_example.php>Return to job control page</a>\n";
463
    page_tail();
464
}
465
466
$action = get_str('action', true);
467
switch ($action) {
468
case '': handle_main(); break;
0 ignored issues
show
The call to handle_main() has too few 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

468
case '': /** @scrutinizer ignore-call */ handle_main(); break;

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
469
case 'abort_batch': handle_abort_batch(); break;
0 ignored issues
show
The call to handle_abort_batch() has too few 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

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

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
470
case 'abort_batch_confirm': handle_abort_batch_confirm(); break;
471
case 'create_action': handle_create_action(); break;
472
case 'create_form': handle_create_form(); break;
473
case 'query_batch': handle_query_batch(); break;
0 ignored issues
show
The call to handle_query_batch() has too few 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

473
case 'query_batch': /** @scrutinizer ignore-call */ handle_query_batch(); break;

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
474
case 'query_job': handle_query_job(); break;
0 ignored issues
show
The call to handle_query_job() has too few 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

474
case 'query_job': /** @scrutinizer ignore-call */ handle_query_job(); break;

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
475
case 'retire_batch': handle_retire_batch(); break;
0 ignored issues
show
The call to handle_retire_batch() has too few 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

475
case 'retire_batch': /** @scrutinizer ignore-call */ handle_retire_batch(); break;

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
476
case 'retire_batch_confirm': handle_retire_batch_confirm(); break;
477
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...
478
    error_page('no such action');
479
}
480
481
?>
482