I am investigating how much resources a particular quiz takes. In the past it has failed once for a large class during a synchronous exam. In the meantime we have done a series of improvements and want to be certain that it won't happen the next time (for the same number of users). Which means I have to simulate the user storm.
A quick-and-dirty PHP script I found in an old post https://moodle.org/mod/forum/discuss.php?d=153580#p671844 would be ideal for our case. The fundamental question is, whether this idea could be extended so that the script will enter the particular quiz, open the five essay type questions it has and download the image in each question? Yes, it is a very special kind of a quiz. It has only five questions, all essay type, the content of each question is an A4-size PNG (which happens to be a page of the exam paper).
The initial try of the script is attached below. So far it looks promising. It is able to log in and open the quiz. Missing is the part visiting each question and ideally downloading the PNG. The latter part may be dropped, if too involved.
The second question: I ran in to "Invalid Login Token" error. Bypassed that with $CFG->disablelogintoken = true; in config.php. Could somebody show me how to get this Login Token from Moodle and paste it to the request?
The script:
===
2 $working_folder = "/tmp";
3 $urlbase = "https://EXAPMLE.COM";
4 $agent = "curl-min";
5 $debug = 1;
6 $cookiefile = tempnam($working_folder, "cookies");
7 $username = "USERNAME";
8 $password = "PASSWORD";
9
10 // get session cookies to set up the Moodle interaction
11 // ----------------------------------------------------
12 $ch = curl_init();
13 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
14 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
15 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
16 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
17 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
18 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
19 curl_setopt($ch, CURLOPT_URL, $urlbase . "/login/index.php");
20 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
21 $result = curl_exec ($ch);
22 curl_close ($ch);
23
24 // login to Moodle
25 // ---------------
26
27 $postfields = array(
28 'username' => $username,
29 'password' => $password,
'testcookies' => '1'
31 );
32
33 $ch = curl_init();
34 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
35 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
36 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
37 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
38 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
39 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
40
41 curl_setopt($ch, CURLOPT_URL, $urlbase . '/login/index.php');
42 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
43 curl_setopt($ch, CURLOPT_POST, 1);
44 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
45 curl_setopt($ch, CURLOPT_HEADER, 1);
46 $result = curl_exec ($ch);
47 curl_close ($ch);
48
49 if (!$result || !preg_match("/HTTP\/1.1 303 See Other/", $result))
50 {
51 unlink($cookiefile);
52 header("HTTP/1.0 403 Forbidden");
53 die("Username/password incorrect.\n");
54 }
55
56 // get session key
57 // ---------------
58 $ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
60 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
61 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
62 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
63 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
64 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
65
66 curl_setopt($ch, CURLOPT_URL, $urlbase . "/mod/quiz /view.php?id=7");
67 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
68 $result = curl_exec ($ch);
69 curl_close ($ch);
===
3 $urlbase = "https://EXAPMLE.COM";
4 $agent = "curl-min";
5 $debug = 1;
6 $cookiefile = tempnam($working_folder, "cookies");
7 $username = "USERNAME";
8 $password = "PASSWORD";
9
10 // get session cookies to set up the Moodle interaction
11 // ----------------------------------------------------
12 $ch = curl_init();
13 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
14 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
15 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
16 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
17 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
18 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
19 curl_setopt($ch, CURLOPT_URL, $urlbase . "/login/index.php");
20 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
21 $result = curl_exec ($ch);
22 curl_close ($ch);
23
24 // login to Moodle
25 // ---------------
26
27 $postfields = array(
28 'username' => $username,
29 'password' => $password,
'testcookies' => '1'
31 );
32
33 $ch = curl_init();
34 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
35 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
36 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
37 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
38 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
39 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
40
41 curl_setopt($ch, CURLOPT_URL, $urlbase . '/login/index.php');
42 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
43 curl_setopt($ch, CURLOPT_POST, 1);
44 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
45 curl_setopt($ch, CURLOPT_HEADER, 1);
46 $result = curl_exec ($ch);
47 curl_close ($ch);
48
49 if (!$result || !preg_match("/HTTP\/1.1 303 See Other/", $result))
50 {
51 unlink($cookiefile);
52 header("HTTP/1.0 403 Forbidden");
53 die("Username/password incorrect.\n");
54 }
55
56 // get session key
57 // ---------------
58 $ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
60 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
61 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
62 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
63 curl_setopt($ch, CURLOPT_VERBOSE, $debug);
64 // if ($debug) curl_setopt($ch, CURLOPT_STDERR, $debughandle);
65
66 curl_setopt($ch, CURLOPT_URL, $urlbase . "/mod/quiz /view.php?id=7");
67 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
68 $result = curl_exec ($ch);
69 curl_close ($ch);
===
Output with debug=1 (no output with debug=0)
===
* Expire in 0 ms for 1 (transfer 0x55a806287950)
[100s of repetitions]
447 * Expire in 0 ms for 1 (transfer 0x55a806287950)
448 * Expire in 1 ms for 1 (transfer 0x55a806287950)
449 * Trying X.X.X.X...
450 * TCP_NODELAY set
451 * Expire in 200 ms for 4 (transfer 0x55a806287950)
452 * Connected to EXAMPLE.COM (X.X.X.X) port 443 (#0)
453 * ALPN, offering h2
454 * ALPN, offering http/1.1
455 * successfully set certificate verify locations:
456 * CAfile: none
457 CApath: /etc/ssl/certs
458 * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
459 * ALPN, server accepted to use http/1.1
460 * Server certificate:
461 * subject: CN=EXAMPLE.COM
462 * start date: Jan 7 17:32:26 2022 GMT
463 * expire date: Apr 7 17:32:25 2022 GMT
464 * subjectAltName: host "EXAMPLE.COM" matched cert's "EXAMPLE.COM"
465 * issuer: C=US; O=Let's Encrypt; CN=R3
466 * SSL certificate verify ok.
467 > GET /login/index.php HTTP/1.1^M
468 Host: EXAMPLE.COM^M
469 User-Agent: curl-min^M
470 Accept: */*^M
471 ^M
472 * old SSL session ID is stale, removing
473 < HTTP/1.1 200 OK^M
474 < Date: Sun, 09 Jan 2022 16:52:31 GMT^M
475 < Server: Apache^M
476 * Added cookie MoodleSession="2bkj2sg7t0e83qadtl8nrphq3l" for domain EXAMPLE.COM, path /, expire 0
477 < Set-Cookie: MoodleSession=2bkj2sg7t0e83qadtl8nrphq3l; path=/; secure^M
478 < Expires: ^M
479 < Cache-Control: private, pre-check=0, post-check=0, max-age=0, no-transform ^M
480 < Pragma: no-cache^M
481 < Content-Language: en^M
482 < Content-Script-Type: text/javascript^M
483 < Content-Style-Type: text/css^M
484 < X-UA-Compatible: IE=edge^M
485 < Accept-Ranges: none^M
486 < X-Frame-Options: sameorigin^M
487 < Vary: Accept-Encoding^M
488 < Transfer-Encoding: chunked^M
489 < Content-Type: text/html; charset=utf-8^M
490 < ^M
491 * Connection #0 to host EXAMPLE.COM left intact
492 * Expire in 0 ms for 6 (transfer 0x55a8062a5c50)
[basically the same pattern repeats]
448 * Expire in 1 ms for 1 (transfer 0x55a806287950)
449 * Trying X.X.X.X...
450 * TCP_NODELAY set
451 * Expire in 200 ms for 4 (transfer 0x55a806287950)
452 * Connected to EXAMPLE.COM (X.X.X.X) port 443 (#0)
453 * ALPN, offering h2
454 * ALPN, offering http/1.1
455 * successfully set certificate verify locations:
456 * CAfile: none
457 CApath: /etc/ssl/certs
458 * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
459 * ALPN, server accepted to use http/1.1
460 * Server certificate:
461 * subject: CN=EXAMPLE.COM
462 * start date: Jan 7 17:32:26 2022 GMT
463 * expire date: Apr 7 17:32:25 2022 GMT
464 * subjectAltName: host "EXAMPLE.COM" matched cert's "EXAMPLE.COM"
465 * issuer: C=US; O=Let's Encrypt; CN=R3
466 * SSL certificate verify ok.
467 > GET /login/index.php HTTP/1.1^M
468 Host: EXAMPLE.COM^M
469 User-Agent: curl-min^M
470 Accept: */*^M
471 ^M
472 * old SSL session ID is stale, removing
473 < HTTP/1.1 200 OK^M
474 < Date: Sun, 09 Jan 2022 16:52:31 GMT^M
475 < Server: Apache^M
476 * Added cookie MoodleSession="2bkj2sg7t0e83qadtl8nrphq3l" for domain EXAMPLE.COM, path /, expire 0
477 < Set-Cookie: MoodleSession=2bkj2sg7t0e83qadtl8nrphq3l; path=/; secure^M
478 < Expires: ^M
479 < Cache-Control: private, pre-check=0, post-check=0, max-age=0, no-transform ^M
480 < Pragma: no-cache^M
481 < Content-Language: en^M
482 < Content-Script-Type: text/javascript^M
483 < Content-Style-Type: text/css^M
484 < X-UA-Compatible: IE=edge^M
485 < Accept-Ranges: none^M
486 < X-Frame-Options: sameorigin^M
487 < Vary: Accept-Encoding^M
488 < Transfer-Encoding: chunked^M
489 < Content-Type: text/html; charset=utf-8^M
490 < ^M
491 * Connection #0 to host EXAMPLE.COM left intact
492 * Expire in 0 ms for 6 (transfer 0x55a8062a5c50)
[basically the same pattern repeats]
===
httpd-access.log
===
[Sun Jan 09 17:30:24.468256 2022] [php7:notice] [pid 762020] [client x.x.x.x:38614] Default exception handler: This quiz attempt no longer exists. Debug: \nError code: attempterrorcontentchangeforuser\n* line 2635 of /mod/quiz/locallib.php: moodle_exception thrown\n* line 44 of /mod/quiz/attempt.php: call to quiz_create_attempt_handling_errors()\n
===
===