MDL-52100 filelib: Update to unit tests for maxbytes.
[moodle.git] / lib / tests / filelib_test.php
CommitLineData
a3d5830a
PS
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
a3d5830a
PS
17/**
18 * Unit tests for /lib/filelib.php.
19 *
20 * @package core_files
21 * @category phpunit
22 * @copyright 2009 Jerome Mouneyrac
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28global $CFG;
29require_once($CFG->libdir . '/filelib.php');
ac29403e 30require_once($CFG->dirroot . '/repository/lib.php');
a3d5830a 31
1d987cb7 32class core_filelib_testcase extends advanced_testcase {
a3d5830a
PS
33 public function test_format_postdata_for_curlcall() {
34
1d987cb7
PS
35 // POST params with just simple types.
36 $postdatatoconvert = array( 'userid' => 1, 'roleid' => 22, 'name' => 'john');
a3d5830a
PS
37 $expectedresult = "userid=1&roleid=22&name=john";
38 $postdata = format_postdata_for_curlcall($postdatatoconvert);
1d987cb7 39 $this->assertEquals($expectedresult, $postdata);
a3d5830a 40
1d987cb7
PS
41 // POST params with a string containing & character.
42 $postdatatoconvert = array( 'name' => 'john&emilie', 'roleid' => 22);
43 $expectedresult = "name=john%26emilie&roleid=22"; // Urlencode: '%26' => '&'.
a3d5830a 44 $postdata = format_postdata_for_curlcall($postdatatoconvert);
1d987cb7 45 $this->assertEquals($expectedresult, $postdata);
a3d5830a 46
1d987cb7
PS
47 // POST params with an empty value.
48 $postdatatoconvert = array( 'name' => null, 'roleid' => 22);
a3d5830a
PS
49 $expectedresult = "name=&roleid=22";
50 $postdata = format_postdata_for_curlcall($postdatatoconvert);
1d987cb7 51 $this->assertEquals($expectedresult, $postdata);
a3d5830a 52
1d987cb7
PS
53 // POST params with complex types.
54 $postdatatoconvert = array( 'users' => array(
a3d5830a
PS
55 array(
56 'id' => 2,
57 'customfields' => array(
58 array
59 (
60 'type' => 'Color',
61 'value' => 'violet'
62 )
63 )
64 )
65 )
66 );
67 $expectedresult = "users[0][id]=2&users[0][customfields][0][type]=Color&users[0][customfields][0][value]=violet";
68 $postdata = format_postdata_for_curlcall($postdatatoconvert);
1d987cb7 69 $this->assertEquals($expectedresult, $postdata);
a3d5830a 70
1d987cb7 71 // POST params with other complex types.
a3d5830a
PS
72 $postdatatoconvert = array ('members' =>
73 array(
74 array('groupid' => 1, 'userid' => 1)
75 , array('groupid' => 1, 'userid' => 2)
76 )
77 );
78 $expectedresult = "members[0][groupid]=1&members[0][userid]=1&members[1][groupid]=1&members[1][userid]=2";
79 $postdata = format_postdata_for_curlcall($postdatatoconvert);
1d987cb7 80 $this->assertEquals($expectedresult, $postdata);
a3d5830a
PS
81 }
82
83 public function test_download_file_content() {
35ea5db0
PS
84 global $CFG;
85
86 // Test http success first.
a9d2f1b4 87 $testhtml = $this->getExternalTestFileUrl('/test.html');
35ea5db0
PS
88
89 $contents = download_file_content($testhtml);
90 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
91
92 $tofile = "$CFG->tempdir/test.html";
93 @unlink($tofile);
94 $result = download_file_content($testhtml, null, null, false, 300, 20, false, $tofile);
95 $this->assertTrue($result);
96 $this->assertFileExists($tofile);
1d987cb7 97 $this->assertSame(file_get_contents($tofile), $contents);
35ea5db0
PS
98 @unlink($tofile);
99
100 $result = download_file_content($testhtml, null, null, false, 300, 20, false, null, true);
101 $this->assertSame($contents, $result);
102
103 $response = download_file_content($testhtml, null, null, true);
104 $this->assertInstanceOf('stdClass', $response);
105 $this->assertSame('200', $response->status);
106 $this->assertTrue(is_array($response->headers));
846f6fbe 107 $this->assertRegExp('|^HTTP/1\.[01] 200 OK$|', rtrim($response->response_code));
35ea5db0
PS
108 $this->assertSame($contents, $response->results);
109 $this->assertSame('', $response->error);
110
35ea5db0 111 // Test https success.
a9d2f1b4 112 $testhtml = $this->getExternalTestFileUrl('/test.html', true);
35ea5db0
PS
113
114 $contents = download_file_content($testhtml, null, null, false, 300, 20, true);
115 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
116
117 $contents = download_file_content($testhtml);
118 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
119
35ea5db0 120 // Now 404.
a9d2f1b4 121 $testhtml = $this->getExternalTestFileUrl('/test.html_nonexistent');
35ea5db0
PS
122
123 $contents = download_file_content($testhtml);
124 $this->assertFalse($contents);
125 $this->assertDebuggingCalled();
126
127 $response = download_file_content($testhtml, null, null, true);
128 $this->assertInstanceOf('stdClass', $response);
129 $this->assertSame('404', $response->status);
130 $this->assertTrue(is_array($response->headers));
846f6fbe 131 $this->assertRegExp('|^HTTP/1\.[01] 404 Not Found$|', rtrim($response->response_code));
b1652d6b 132 // Do not test the response starts with DOCTYPE here because some servers may return different headers.
35ea5db0
PS
133 $this->assertSame('', $response->error);
134
35ea5db0 135 // Invalid url.
a9d2f1b4
PS
136 $testhtml = $this->getExternalTestFileUrl('/test.html');
137 $testhtml = str_replace('http://', 'ftp://', $testhtml);
35ea5db0 138
a3d5830a 139 $contents = download_file_content($testhtml);
35ea5db0
PS
140 $this->assertFalse($contents);
141
35ea5db0 142 // Test standard redirects.
a9d2f1b4 143 $testurl = $this->getExternalTestFileUrl('/test_redir.php');
35ea5db0
PS
144
145 $contents = download_file_content("$testurl?redir=2");
146 $this->assertSame('done', $contents);
147
148 $response = download_file_content("$testurl?redir=2", null, null, true);
149 $this->assertInstanceOf('stdClass', $response);
150 $this->assertSame('200', $response->status);
151 $this->assertTrue(is_array($response->headers));
846f6fbe 152 $this->assertRegExp('|^HTTP/1\.[01] 200 OK$|', rtrim($response->response_code));
35ea5db0
PS
153 $this->assertSame('done', $response->results);
154 $this->assertSame('', $response->error);
155
a9d2f1b4 156 // Commented out this block if there are performance problems.
1d987cb7 157 /*
35ea5db0
PS
158 $contents = download_file_content("$testurl?redir=6");
159 $this->assertFalse(false, $contents);
160 $this->assertDebuggingCalled();
35ea5db0
PS
161 $response = download_file_content("$testurl?redir=6", null, null, true);
162 $this->assertInstanceOf('stdClass', $response);
163 $this->assertSame('0', $response->status);
164 $this->assertTrue(is_array($response->headers));
165 $this->assertFalse($response->results);
166 $this->assertNotEmpty($response->error);
1d987cb7 167 */
35ea5db0
PS
168
169 // Test relative redirects.
a9d2f1b4 170 $testurl = $this->getExternalTestFileUrl('/test_relative_redir.php');
35ea5db0
PS
171
172 $contents = download_file_content("$testurl");
173 $this->assertSame('done', $contents);
174
175 $contents = download_file_content("$testurl?unused=xxx");
176 $this->assertSame('done', $contents);
177 }
178
179 /**
74c4405b 180 * Test curl basics.
35ea5db0 181 */
74c4405b 182 public function test_curl_basics() {
35ea5db0
PS
183 global $CFG;
184
74c4405b 185 // Test HTTP success.
a9d2f1b4 186 $testhtml = $this->getExternalTestFileUrl('/test.html');
35ea5db0
PS
187
188 $curl = new curl();
189 $contents = $curl->get($testhtml);
190 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
191 $this->assertSame(0, $curl->get_errno());
192
193 $curl = new curl();
194 $tofile = "$CFG->tempdir/test.html";
195 @unlink($tofile);
196 $fp = fopen($tofile, 'w');
197 $result = $curl->get($testhtml, array(), array('CURLOPT_FILE'=>$fp));
198 $this->assertTrue($result);
199 fclose($fp);
200 $this->assertFileExists($tofile);
201 $this->assertSame($contents, file_get_contents($tofile));
202 @unlink($tofile);
203
204 $curl = new curl();
205 $tofile = "$CFG->tempdir/test.html";
206 @unlink($tofile);
207 $result = $curl->download_one($testhtml, array(), array('filepath'=>$tofile));
208 $this->assertTrue($result);
209 $this->assertFileExists($tofile);
210 $this->assertSame($contents, file_get_contents($tofile));
211 @unlink($tofile);
212
74c4405b
FM
213 // Test 404 request.
214 $curl = new curl();
215 $contents = $curl->get($this->getExternalTestFileUrl('/i.do.not.exist'));
216 $response = $curl->getResponse();
217 $this->assertSame('404 Not Found', reset($response));
218 $this->assertSame(0, $curl->get_errno());
219 }
220
605bab84
JD
221 /**
222 * Test a curl basic request with security enabled.
223 */
224 public function test_curl_basics_with_security_helper() {
225 $this->resetAfterTest();
226
227 // Test a request with a basic hostname filter applied.
228 $testhtml = $this->getExternalTestFileUrl('/test.html');
229 $url = new moodle_url($testhtml);
230 $host = $url->get_host();
231 set_config('curlsecurityblockedhosts', $host); // Blocks $host.
232
233 // Create curl with the default security enabled. We expect this to be blocked.
234 $curl = new curl();
235 $contents = $curl->get($testhtml);
236 $expected = $curl->get_security()->get_blocked_url_string();
237 $this->assertSame($expected, $contents);
238 $this->assertSame(0, $curl->get_errno());
239
240 // Now, create a curl using the 'ignoresecurity' override.
241 // We expect this request to pass, despite the admin setting having been set earlier.
242 $curl = new curl(['ignoresecurity' => true]);
243 $contents = $curl->get($testhtml);
244 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
245 $this->assertSame(0, $curl->get_errno());
246
247 // Now, try injecting a mock security helper into curl. This will override the default helper.
248 $mockhelper = $this->getMockBuilder('\core\files\curl_security_helper')->getMock();
249
250 // Make the mock return a different string.
251 $mockhelper->expects($this->any())->method('get_blocked_url_string')->will($this->returnValue('You shall not pass'));
252
253 // And make the mock security helper block all URLs. This helper instance doesn't care about config.
254 $mockhelper->expects($this->any())->method('url_is_blocked')->will($this->returnValue(true));
255
256 $curl = new curl(['securityhelper' => $mockhelper]);
257 $contents = $curl->get($testhtml);
258 $this->assertSame('You shall not pass', $curl->get_security()->get_blocked_url_string());
259 $this->assertSame($curl->get_security()->get_blocked_url_string(), $contents);
260 }
261
74c4405b
FM
262 public function test_curl_redirects() {
263 global $CFG;
264
35ea5db0 265 // Test full URL redirects.
a9d2f1b4 266 $testurl = $this->getExternalTestFileUrl('/test_redir.php');
35ea5db0
PS
267
268 $curl = new curl();
269 $contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>2));
74c4405b
FM
270 $response = $curl->getResponse();
271 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
272 $this->assertSame(0, $curl->get_errno());
273 $this->assertSame(2, $curl->info['redirect_count']);
274 $this->assertSame('done', $contents);
275
276 $curl = new curl();
277 $curl->emulateredirects = true;
278 $contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>2));
74c4405b
FM
279 $response = $curl->getResponse();
280 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
281 $this->assertSame(0, $curl->get_errno());
282 $this->assertSame(2, $curl->info['redirect_count']);
283 $this->assertSame('done', $contents);
284
90048c7c
TH
285 // This test was failing for people behind Squid proxies. Squid does not
286 // fully support HTTP 1.1, so converts things to HTTP 1.0, where the name
287 // of the status code is different.
288 reset($response);
289 if (key($response) === 'HTTP/1.0') {
290 $responsecode302 = '302 Moved Temporarily';
291 } else {
292 $responsecode302 = '302 Found';
293 }
294
35ea5db0
PS
295 $curl = new curl();
296 $contents = $curl->get("$testurl?redir=3", array(), array('CURLOPT_FOLLOWLOCATION'=>0));
74c4405b 297 $response = $curl->getResponse();
90048c7c 298 $this->assertSame($responsecode302, reset($response));
35ea5db0
PS
299 $this->assertSame(0, $curl->get_errno());
300 $this->assertSame(302, $curl->info['http_code']);
301 $this->assertSame('', $contents);
302
303 $curl = new curl();
304 $curl->emulateredirects = true;
305 $contents = $curl->get("$testurl?redir=3", array(), array('CURLOPT_FOLLOWLOCATION'=>0));
74c4405b 306 $response = $curl->getResponse();
90048c7c 307 $this->assertSame($responsecode302, reset($response));
35ea5db0
PS
308 $this->assertSame(0, $curl->get_errno());
309 $this->assertSame(302, $curl->info['http_code']);
310 $this->assertSame('', $contents);
311
312 $curl = new curl();
313 $contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>1));
314 $this->assertSame(CURLE_TOO_MANY_REDIRECTS, $curl->get_errno());
315 $this->assertNotEmpty($contents);
316
317 $curl = new curl();
318 $curl->emulateredirects = true;
319 $contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>1));
320 $this->assertSame(CURLE_TOO_MANY_REDIRECTS, $curl->get_errno());
321 $this->assertNotEmpty($contents);
322
323 $curl = new curl();
324 $tofile = "$CFG->tempdir/test.html";
325 @unlink($tofile);
326 $fp = fopen($tofile, 'w');
327 $result = $curl->get("$testurl?redir=1", array(), array('CURLOPT_FILE'=>$fp));
328 $this->assertTrue($result);
329 fclose($fp);
330 $this->assertFileExists($tofile);
331 $this->assertSame('done', file_get_contents($tofile));
332 @unlink($tofile);
333
334 $curl = new curl();
335 $curl->emulateredirects = true;
336 $tofile = "$CFG->tempdir/test.html";
337 @unlink($tofile);
338 $fp = fopen($tofile, 'w');
339 $result = $curl->get("$testurl?redir=1", array(), array('CURLOPT_FILE'=>$fp));
340 $this->assertTrue($result);
341 fclose($fp);
342 $this->assertFileExists($tofile);
343 $this->assertSame('done', file_get_contents($tofile));
344 @unlink($tofile);
345
346 $curl = new curl();
347 $tofile = "$CFG->tempdir/test.html";
348 @unlink($tofile);
349 $result = $curl->download_one("$testurl?redir=1", array(), array('filepath'=>$tofile));
350 $this->assertTrue($result);
351 $this->assertFileExists($tofile);
352 $this->assertSame('done', file_get_contents($tofile));
353 @unlink($tofile);
354
355 $curl = new curl();
356 $curl->emulateredirects = true;
357 $tofile = "$CFG->tempdir/test.html";
358 @unlink($tofile);
359 $result = $curl->download_one("$testurl?redir=1", array(), array('filepath'=>$tofile));
360 $this->assertTrue($result);
361 $this->assertFileExists($tofile);
362 $this->assertSame('done', file_get_contents($tofile));
363 @unlink($tofile);
74c4405b 364 }
35ea5db0 365
74c4405b 366 public function test_curl_relative_redirects() {
35ea5db0 367 // Test relative location redirects.
a9d2f1b4 368 $testurl = $this->getExternalTestFileUrl('/test_relative_redir.php');
35ea5db0
PS
369
370 $curl = new curl();
371 $contents = $curl->get($testurl);
74c4405b
FM
372 $response = $curl->getResponse();
373 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
374 $this->assertSame(0, $curl->get_errno());
375 $this->assertSame(1, $curl->info['redirect_count']);
376 $this->assertSame('done', $contents);
377
378 $curl = new curl();
379 $curl->emulateredirects = true;
380 $contents = $curl->get($testurl);
74c4405b
FM
381 $response = $curl->getResponse();
382 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
383 $this->assertSame(0, $curl->get_errno());
384 $this->assertSame(1, $curl->info['redirect_count']);
385 $this->assertSame('done', $contents);
386
35ea5db0 387 // Test different redirect types.
a9d2f1b4 388 $testurl = $this->getExternalTestFileUrl('/test_relative_redir.php');
35ea5db0
PS
389
390 $curl = new curl();
391 $contents = $curl->get("$testurl?type=301");
74c4405b
FM
392 $response = $curl->getResponse();
393 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
394 $this->assertSame(0, $curl->get_errno());
395 $this->assertSame(1, $curl->info['redirect_count']);
396 $this->assertSame('done', $contents);
397
398 $curl = new curl();
399 $curl->emulateredirects = true;
400 $contents = $curl->get("$testurl?type=301");
74c4405b
FM
401 $response = $curl->getResponse();
402 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
403 $this->assertSame(0, $curl->get_errno());
404 $this->assertSame(1, $curl->info['redirect_count']);
405 $this->assertSame('done', $contents);
406
407 $curl = new curl();
408 $contents = $curl->get("$testurl?type=302");
74c4405b
FM
409 $response = $curl->getResponse();
410 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
411 $this->assertSame(0, $curl->get_errno());
412 $this->assertSame(1, $curl->info['redirect_count']);
413 $this->assertSame('done', $contents);
414
415 $curl = new curl();
416 $curl->emulateredirects = true;
417 $contents = $curl->get("$testurl?type=302");
74c4405b
FM
418 $response = $curl->getResponse();
419 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
420 $this->assertSame(0, $curl->get_errno());
421 $this->assertSame(1, $curl->info['redirect_count']);
422 $this->assertSame('done', $contents);
423
424 $curl = new curl();
425 $contents = $curl->get("$testurl?type=303");
74c4405b
FM
426 $response = $curl->getResponse();
427 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
428 $this->assertSame(0, $curl->get_errno());
429 $this->assertSame(1, $curl->info['redirect_count']);
430 $this->assertSame('done', $contents);
431
432 $curl = new curl();
433 $curl->emulateredirects = true;
434 $contents = $curl->get("$testurl?type=303");
74c4405b
FM
435 $response = $curl->getResponse();
436 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
437 $this->assertSame(0, $curl->get_errno());
438 $this->assertSame(1, $curl->info['redirect_count']);
439 $this->assertSame('done', $contents);
440
441 $curl = new curl();
442 $contents = $curl->get("$testurl?type=307");
74c4405b
FM
443 $response = $curl->getResponse();
444 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
445 $this->assertSame(0, $curl->get_errno());
446 $this->assertSame(1, $curl->info['redirect_count']);
447 $this->assertSame('done', $contents);
448
449 $curl = new curl();
450 $curl->emulateredirects = true;
451 $contents = $curl->get("$testurl?type=307");
74c4405b
FM
452 $response = $curl->getResponse();
453 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
454 $this->assertSame(0, $curl->get_errno());
455 $this->assertSame(1, $curl->info['redirect_count']);
456 $this->assertSame('done', $contents);
457
458 $curl = new curl();
459 $contents = $curl->get("$testurl?type=308");
74c4405b
FM
460 $response = $curl->getResponse();
461 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
462 $this->assertSame(0, $curl->get_errno());
463 $this->assertSame(1, $curl->info['redirect_count']);
464 $this->assertSame('done', $contents);
465
466 $curl = new curl();
467 $curl->emulateredirects = true;
468 $contents = $curl->get("$testurl?type=308");
74c4405b
FM
469 $response = $curl->getResponse();
470 $this->assertSame('200 OK', reset($response));
35ea5db0
PS
471 $this->assertSame(0, $curl->get_errno());
472 $this->assertSame(1, $curl->info['redirect_count']);
473 $this->assertSame('done', $contents);
ba72e295 474
74c4405b
FM
475 }
476
477 public function test_curl_proxybypass() {
478 global $CFG;
479 $testurl = $this->getExternalTestFileUrl('/test.html');
480
ba72e295
FM
481 $oldproxy = $CFG->proxyhost;
482 $oldproxybypass = $CFG->proxybypass;
483
484 // Test without proxy bypass and inaccessible proxy.
485 $CFG->proxyhost = 'i.do.not.exist';
486 $CFG->proxybypass = '';
487 $curl = new curl();
74c4405b 488 $contents = $curl->get($testurl);
ba72e295
FM
489 $this->assertNotEquals(0, $curl->get_errno());
490 $this->assertNotEquals('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
491
492 // Test with proxy bypass.
74c4405b
FM
493 $testurlhost = parse_url($testurl, PHP_URL_HOST);
494 $CFG->proxybypass = $testurlhost;
ba72e295 495 $curl = new curl();
74c4405b 496 $contents = $curl->get($testurl);
ba72e295
FM
497 $this->assertSame(0, $curl->get_errno());
498 $this->assertSame('47250a973d1b88d9445f94db4ef2c97a', md5($contents));
499
500 $CFG->proxyhost = $oldproxy;
501 $CFG->proxybypass = $oldproxybypass;
a3d5830a 502 }
67233725 503
74c4405b
FM
504 public function test_curl_post() {
505 $testurl = $this->getExternalTestFileUrl('/test_post.php');
102230b2
FM
506
507 // Test post request.
508 $curl = new curl();
74c4405b 509 $contents = $curl->post($testurl, 'data=moodletest');
102230b2
FM
510 $response = $curl->getResponse();
511 $this->assertSame('200 OK', reset($response));
512 $this->assertSame(0, $curl->get_errno());
513 $this->assertSame('OK', $contents);
514
515 // Test 100 requests.
516 $curl = new curl();
517 $curl->setHeader('Expect: 100-continue');
74c4405b 518 $contents = $curl->post($testurl, 'data=moodletest');
102230b2
FM
519 $response = $curl->getResponse();
520 $this->assertSame('200 OK', reset($response));
521 $this->assertSame(0, $curl->get_errno());
522 $this->assertSame('OK', $contents);
523 }
524
218d751d
FM
525 public function test_curl_file() {
526 $this->resetAfterTest();
527 $testurl = $this->getExternalTestFileUrl('/test_file.php');
528
529 $fs = get_file_storage();
530 $filerecord = array(
531 'contextid' => context_system::instance()->id,
532 'component' => 'test',
533 'filearea' => 'curl_post',
534 'itemid' => 0,
535 'filepath' => '/',
536 'filename' => 'test.txt'
537 );
538 $teststring = 'moodletest';
539 $testfile = $fs->create_file_from_string($filerecord, $teststring);
540
541 // Test post with file.
542 $data = array('testfile' => $testfile);
543 $curl = new curl();
544 $contents = $curl->post($testurl, $data);
545 $this->assertSame('OK', $contents);
546 }
547
b1eb6dd7
MC
548 public function test_curl_file_name() {
549 $this->resetAfterTest();
550 $testurl = $this->getExternalTestFileUrl('/test_file_name.php');
551
552 $fs = get_file_storage();
553 $filerecord = array(
554 'contextid' => context_system::instance()->id,
555 'component' => 'test',
556 'filearea' => 'curl_post',
557 'itemid' => 0,
558 'filepath' => '/',
559 'filename' => 'test.txt'
560 );
561 $teststring = 'moodletest';
562 $testfile = $fs->create_file_from_string($filerecord, $teststring);
563
564 // Test post with file.
565 $data = array('testfile' => $testfile);
566 $curl = new curl();
567 $contents = $curl->post($testurl, $data);
568 $this->assertSame('OK', $contents);
569 }
570
38a73bf4
FM
571 public function test_curl_protocols() {
572
573 // HTTP and HTTPS requests were verified in previous requests. Now check
574 // that we can selectively disable some protocols.
575 $curl = new curl();
576
577 // Other protocols than HTTP(S) are disabled by default.
578 $testurl = 'file:///';
579 $curl->get($testurl);
580 $this->assertNotEmpty($curl->error);
581 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
582
583 $testurl = 'ftp://nowhere';
584 $curl->get($testurl);
585 $this->assertNotEmpty($curl->error);
586 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
587
588 $testurl = 'telnet://somewhere';
589 $curl->get($testurl);
590 $this->assertNotEmpty($curl->error);
591 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
592
593 // Protocols are also disabled during redirections.
594 $testurl = $this->getExternalTestFileUrl('/test_redir_proto.php');
595 $curl->get($testurl, array('proto' => 'file'));
596 $this->assertNotEmpty($curl->error);
597 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
598
599 $testurl = $this->getExternalTestFileUrl('/test_redir_proto.php');
600 $curl->get($testurl, array('proto' => 'ftp'));
601 $this->assertNotEmpty($curl->error);
602 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
603
604 $testurl = $this->getExternalTestFileUrl('/test_redir_proto.php');
605 $curl->get($testurl, array('proto' => 'telnet'));
606 $this->assertNotEmpty($curl->error);
607 $this->assertEquals(CURLE_UNSUPPORTED_PROTOCOL, $curl->errno);
608 }
609
67233725
DC
610 /**
611 * Testing prepare draft area
612 *
613 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
614 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
615 */
616 public function test_prepare_draft_area() {
617 global $USER, $DB;
618
619 $this->resetAfterTest(true);
620
621 $generator = $this->getDataGenerator();
622 $user = $generator->create_user();
623 $usercontext = context_user::instance($user->id);
624 $USER = $DB->get_record('user', array('id'=>$user->id));
625
7051415c
DC
626 $repositorypluginname = 'user';
627
628 $args = array();
629 $args['type'] = $repositorypluginname;
630 $repos = repository::get_instances($args);
631 $userrepository = reset($repos);
632 $this->assertInstanceOf('repository', $userrepository);
67233725
DC
633
634 $fs = get_file_storage();
7051415c 635
67233725
DC
636 $syscontext = context_system::instance();
637 $component = 'core';
638 $filearea = 'unittest';
639 $itemid = 0;
640 $filepath = '/';
641 $filename = 'test.txt';
642 $sourcefield = 'Copyright stuff';
643
644 $filerecord = array(
645 'contextid' => $syscontext->id,
646 'component' => $component,
647 'filearea' => $filearea,
648 'itemid' => $itemid,
649 'filepath' => $filepath,
650 'filename' => $filename,
651 'source' => $sourcefield,
652 );
653 $ref = $fs->pack_reference($filerecord);
67233725 654 $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
67233725
DC
655 $fileid = $originalfile->get_id();
656 $this->assertInstanceOf('stored_file', $originalfile);
657
1d987cb7 658 // Create a user private file.
7051415c
DC
659 $userfilerecord = new stdClass;
660 $userfilerecord->contextid = $usercontext->id;
661 $userfilerecord->component = 'user';
662 $userfilerecord->filearea = 'private';
663 $userfilerecord->itemid = 0;
664 $userfilerecord->filepath = '/';
665 $userfilerecord->filename = 'userfile.txt';
666 $userfilerecord->source = 'test';
667 $userfile = $fs->create_file_from_string($userfilerecord, 'User file content');
668 $userfileref = $fs->pack_reference($userfilerecord);
669
670 $filerefrecord = clone((object)$filerecord);
671 $filerefrecord->filename = 'testref.txt';
1d987cb7
PS
672
673 // Create a file reference.
7051415c
DC
674 $fileref = $fs->create_file_from_reference($filerefrecord, $userrepository->id, $userfileref);
675 $this->assertInstanceOf('stored_file', $fileref);
291a3d1f 676 $this->assertEquals($userrepository->id, $fileref->get_repository_id());
1d987cb7 677 $this->assertSame($userfile->get_contenthash(), $fileref->get_contenthash());
7051415c
DC
678 $this->assertEquals($userfile->get_filesize(), $fileref->get_filesize());
679 $this->assertRegExp('#' . $userfile->get_filename(). '$#', $fileref->get_reference_details());
680
67233725
DC
681 $draftitemid = 0;
682 file_prepare_draft_area($draftitemid, $syscontext->id, $component, $filearea, $itemid);
683
684 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid);
1d987cb7 685 $this->assertCount(3, $draftfiles);
67233725
DC
686
687 $draftfile = $fs->get_file($usercontext->id, 'user', 'draft', $draftitemid, $filepath, $filename);
688 $source = unserialize($draftfile->get_source());
1d987cb7
PS
689 $this->assertSame($ref, $source->original);
690 $this->assertSame($sourcefield, $source->source);
67233725 691
7051415c
DC
692 $draftfileref = $fs->get_file($usercontext->id, 'user', 'draft', $draftitemid, $filepath, $filerefrecord->filename);
693 $this->assertInstanceOf('stored_file', $draftfileref);
1d987cb7 694 $this->assertTrue($draftfileref->is_external_file());
67233725 695
1d987cb7 696 // Change some information.
67233725
DC
697 $author = 'Dongsheng Cai';
698 $draftfile->set_author($author);
7051415c 699 $newsourcefield = 'Get from Flickr';
67233725
DC
700 $license = 'GPLv3';
701 $draftfile->set_license($license);
1d987cb7 702 // If you want to really just change source field, do this.
67233725
DC
703 $source = unserialize($draftfile->get_source());
704 $newsourcefield = 'From flickr';
705 $source->source = $newsourcefield;
706 $draftfile->set_source(serialize($source));
707
1d987cb7 708 // Save changed file.
67233725
DC
709 file_save_draft_area_files($draftitemid, $syscontext->id, $component, $filearea, $itemid);
710
711 $file = $fs->get_file($syscontext->id, $component, $filearea, $itemid, $filepath, $filename);
712
1d987cb7 713 // Make sure it's the original file id.
67233725
DC
714 $this->assertEquals($fileid, $file->get_id());
715 $this->assertInstanceOf('stored_file', $file);
1d987cb7
PS
716 $this->assertSame($author, $file->get_author());
717 $this->assertSame($license, $file->get_license());
67233725
DC
718 $this->assertEquals($newsourcefield, $file->get_source());
719 }
61506a0a
DC
720
721 /**
1d987cb7 722 * Testing deleting original files.
61506a0a
DC
723 *
724 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
725 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
726 */
727 public function test_delete_original_file_from_draft() {
728 global $USER, $DB;
729
730 $this->resetAfterTest(true);
731
732 $generator = $this->getDataGenerator();
733 $user = $generator->create_user();
734 $usercontext = context_user::instance($user->id);
735 $USER = $DB->get_record('user', array('id'=>$user->id));
736
737 $repositorypluginname = 'user';
738
739 $args = array();
740 $args['type'] = $repositorypluginname;
741 $repos = repository::get_instances($args);
742 $userrepository = reset($repos);
743 $this->assertInstanceOf('repository', $userrepository);
744
745 $fs = get_file_storage();
746 $syscontext = context_system::instance();
747
748 $filecontent = 'User file content';
749
1d987cb7 750 // Create a user private file.
61506a0a
DC
751 $userfilerecord = new stdClass;
752 $userfilerecord->contextid = $usercontext->id;
753 $userfilerecord->component = 'user';
754 $userfilerecord->filearea = 'private';
755 $userfilerecord->itemid = 0;
756 $userfilerecord->filepath = '/';
757 $userfilerecord->filename = 'userfile.txt';
758 $userfilerecord->source = 'test';
759 $userfile = $fs->create_file_from_string($userfilerecord, $filecontent);
760 $userfileref = $fs->pack_reference($userfilerecord);
761 $contenthash = $userfile->get_contenthash();
762
763 $filerecord = array(
764 'contextid' => $syscontext->id,
765 'component' => 'core',
766 'filearea' => 'phpunit',
767 'itemid' => 0,
768 'filepath' => '/',
769 'filename' => 'test.txt',
770 );
1d987cb7 771 // Create a file reference.
61506a0a
DC
772 $fileref = $fs->create_file_from_reference($filerecord, $userrepository->id, $userfileref);
773 $this->assertInstanceOf('stored_file', $fileref);
291a3d1f 774 $this->assertEquals($userrepository->id, $fileref->get_repository_id());
1d987cb7 775 $this->assertSame($userfile->get_contenthash(), $fileref->get_contenthash());
61506a0a
DC
776 $this->assertEquals($userfile->get_filesize(), $fileref->get_filesize());
777 $this->assertRegExp('#' . $userfile->get_filename(). '$#', $fileref->get_reference_details());
778
779 $draftitemid = 0;
780 file_prepare_draft_area($draftitemid, $usercontext->id, 'user', 'private', 0);
781 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid);
1d987cb7 782 $this->assertCount(2, $draftfiles);
61506a0a
DC
783 $draftfile = $fs->get_file($usercontext->id, 'user', 'draft', $draftitemid, $userfilerecord->filepath, $userfilerecord->filename);
784 $draftfile->delete();
1d987cb7 785 // Save changed file.
61506a0a
DC
786 file_save_draft_area_files($draftitemid, $usercontext->id, 'user', 'private', 0);
787
1d987cb7 788 // The file reference should be a regular moodle file now.
61506a0a 789 $fileref = $fs->get_file($syscontext->id, 'core', 'phpunit', 0, '/', 'test.txt');
1d987cb7
PS
790 $this->assertFalse($fileref->is_external_file());
791 $this->assertSame($contenthash, $fileref->get_contenthash());
61506a0a
DC
792 $this->assertEquals($filecontent, $fileref->get_content());
793 }
85cb4b65 794
795 /**
796 * Tests the strip_double_headers function in the curl class.
797 */
798 public function test_curl_strip_double_headers() {
799 // Example from issue tracker.
800 $mdl30648example = <<<EOF
801HTTP/1.0 407 Proxy Authentication Required
802Server: squid/2.7.STABLE9
803Date: Thu, 08 Dec 2011 14:44:33 GMT
804Content-Type: text/html
805Content-Length: 1275
806X-Squid-Error: ERR_CACHE_ACCESS_DENIED 0
807Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
808X-Cache: MISS from homer.lancs.ac.uk
809X-Cache-Lookup: NONE from homer.lancs.ac.uk:3128
810Via: 1.0 homer.lancs.ac.uk:3128 (squid/2.7.STABLE9)
811Connection: close
812
813HTTP/1.0 200 OK
814Server: Apache
815X-Lb-Nocache: true
c3a3f540 816Cache-Control: private, max-age=15, no-transform
85cb4b65 817ETag: "4d69af5d8ba873ea9192c489e151bd7b"
818Content-Type: text/html
819Date: Thu, 08 Dec 2011 14:44:53 GMT
820Set-Cookie: BBC-UID=c4de2e109c8df6a51de627cee11b214bd4fb6054a030222488317afb31b343360MoodleBot/1.0; expires=Mon, 07-Dec-15 14:44:53 GMT; path=/; domain=bbc.co.uk
821X-Cache-Action: MISS
822X-Cache-Age: 0
823Vary: Cookie,X-Country,X-Ip-is-uk-combined,X-Ip-is-advertise-combined,X-Ip_is_uk_combined,X-Ip_is_advertise_combined, X-GeoIP
824X-Cache: MISS from ww
825
826<html>...
827EOF;
828 $mdl30648expected = <<<EOF
829HTTP/1.0 200 OK
830Server: Apache
831X-Lb-Nocache: true
c3a3f540 832Cache-Control: private, max-age=15, no-transform
85cb4b65 833ETag: "4d69af5d8ba873ea9192c489e151bd7b"
834Content-Type: text/html
835Date: Thu, 08 Dec 2011 14:44:53 GMT
836Set-Cookie: BBC-UID=c4de2e109c8df6a51de627cee11b214bd4fb6054a030222488317afb31b343360MoodleBot/1.0; expires=Mon, 07-Dec-15 14:44:53 GMT; path=/; domain=bbc.co.uk
837X-Cache-Action: MISS
838X-Cache-Age: 0
839Vary: Cookie,X-Country,X-Ip-is-uk-combined,X-Ip-is-advertise-combined,X-Ip_is_uk_combined,X-Ip_is_advertise_combined, X-GeoIP
840X-Cache: MISS from ww
841
842<html>...
843EOF;
844 // For HTTP, replace the \n with \r\n.
845 $mdl30648example = preg_replace("~(?!<\r)\n~", "\r\n", $mdl30648example);
846 $mdl30648expected = preg_replace("~(?!<\r)\n~", "\r\n", $mdl30648expected);
847
848 // Test stripping works OK.
1d987cb7 849 $this->assertSame($mdl30648expected, curl::strip_double_headers($mdl30648example));
85cb4b65 850 // Test it does nothing to the 'plain' data.
1d987cb7 851 $this->assertSame($mdl30648expected, curl::strip_double_headers($mdl30648expected));
85cb4b65 852
853 // Example from OU proxy.
854 $httpsexample = <<<EOF
855HTTP/1.0 200 Connection established
856
857HTTP/1.1 200 OK
858Date: Fri, 22 Feb 2013 17:14:23 GMT
859Server: Apache/2
860X-Powered-By: PHP/5.3.3-7+squeeze14
861Content-Type: text/xml
862Connection: close
863Content-Encoding: gzip
864Transfer-Encoding: chunked
865
866<?xml version="1.0" encoding="ISO-8859-1" ?>
867<rss version="2.0">...
868EOF;
869 $httpsexpected = <<<EOF
870HTTP/1.1 200 OK
871Date: Fri, 22 Feb 2013 17:14:23 GMT
872Server: Apache/2
873X-Powered-By: PHP/5.3.3-7+squeeze14
874Content-Type: text/xml
875Connection: close
876Content-Encoding: gzip
877Transfer-Encoding: chunked
878
879<?xml version="1.0" encoding="ISO-8859-1" ?>
880<rss version="2.0">...
881EOF;
882 // For HTTP, replace the \n with \r\n.
883 $httpsexample = preg_replace("~(?!<\r)\n~", "\r\n", $httpsexample);
884 $httpsexpected = preg_replace("~(?!<\r)\n~", "\r\n", $httpsexpected);
885
886 // Test stripping works OK.
1d987cb7 887 $this->assertSame($httpsexpected, curl::strip_double_headers($httpsexample));
85cb4b65 888 // Test it does nothing to the 'plain' data.
1d987cb7 889 $this->assertSame($httpsexpected, curl::strip_double_headers($httpsexpected));
85cb4b65 890 }
91fed57a 891
892 /**
893 * Tests the get_mimetype_description function.
894 */
895 public function test_get_mimetype_description() {
896 $this->resetAfterTest();
897
898 // Test example type (.doc).
899 $this->assertEquals(get_string('application/msword', 'mimetypes'),
900 get_mimetype_description(array('filename' => 'test.doc')));
901
902 // Test an unknown file type.
903 $this->assertEquals(get_string('document/unknown', 'mimetypes'),
904 get_mimetype_description(array('filename' => 'test.frog')));
905
906 // Test a custom filetype with no lang string specified.
907 core_filetypes::add_type('frog', 'application/x-frog', 'document');
908 $this->assertEquals('application/x-frog',
909 get_mimetype_description(array('filename' => 'test.frog')));
910
911 // Test custom description.
912 core_filetypes::update_type('frog', 'frog', 'application/x-frog', 'document',
913 array(), '', 'Froggy file');
914 $this->assertEquals('Froggy file',
915 get_mimetype_description(array('filename' => 'test.frog')));
916
917 // Test custom description using multilang filter.
e37c1286 918 filter_manager::reset_caches();
91fed57a 919 filter_set_global_state('multilang', TEXTFILTER_ON);
920 filter_set_applies_to_strings('multilang', true);
921 core_filetypes::update_type('frog', 'frog', 'application/x-frog', 'document',
922 array(), '', '<span lang="en" class="multilang">Green amphibian</span>' .
923 '<span lang="fr" class="multilang">Amphibian vert</span>');
924 $this->assertEquals('Green amphibian',
925 get_mimetype_description(array('filename' => 'test.frog')));
926 }
927
928 /**
929 * Tests the get_mimetypes_array function.
930 */
931 public function test_get_mimetypes_array() {
932 $mimeinfo = get_mimetypes_array();
933
934 // Test example MIME type (doc).
935 $this->assertEquals('application/msword', $mimeinfo['doc']['type']);
936 $this->assertEquals('document', $mimeinfo['doc']['icon']);
937 $this->assertEquals(array('document'), $mimeinfo['doc']['groups']);
938 $this->assertFalse(isset($mimeinfo['doc']['string']));
939 $this->assertFalse(isset($mimeinfo['doc']['defaulticon']));
940 $this->assertFalse(isset($mimeinfo['doc']['customdescription']));
941
942 // Check the less common fields using other examples.
943 $this->assertEquals('image', $mimeinfo['png']['string']);
944 $this->assertEquals(true, $mimeinfo['txt']['defaulticon']);
945 }
cbb7c6a9 946
0c4c3b9a
JP
947 /**
948 * Tests for get_mimetype_for_sending function.
949 */
950 public function test_get_mimetype_for_sending() {
951 // Without argument.
952 $this->assertEquals('application/octet-stream', get_mimetype_for_sending());
953
954 // Argument is null.
955 $this->assertEquals('application/octet-stream', get_mimetype_for_sending(null));
956
957 // Filename having no extension.
958 $this->assertEquals('application/octet-stream', get_mimetype_for_sending('filenamewithoutextension'));
959
960 // Test using the extensions listed from the get_mimetypes_array function.
961 $mimetypes = get_mimetypes_array();
962 foreach ($mimetypes as $ext => $info) {
963 if ($ext === 'xxx') {
964 $this->assertEquals('application/octet-stream', get_mimetype_for_sending('SampleFile.' . $ext));
965 } else {
966 $this->assertEquals($info['type'], get_mimetype_for_sending('SampleFile.' . $ext));
967 }
968 }
969 }
970
cbb7c6a9
DC
971 /**
972 * Test curl agent settings.
973 */
974 public function test_curl_useragent() {
9a1adda5 975 $curl = new testable_curl();
cbb7c6a9
DC
976 $options = $curl->get_options();
977 $this->assertNotEmpty($options);
978
979 $curl->call_apply_opt($options);
980 $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header));
981 $this->assertFalse(in_array('User-Agent: Test/1.0', $curl->header));
982
983 $options['CURLOPT_USERAGENT'] = 'Test/1.0';
984 $curl->call_apply_opt($options);
985 $this->assertTrue(in_array('User-Agent: Test/1.0', $curl->header));
986 $this->assertFalse(in_array('User-Agent: MoodleBot/1.0', $curl->header));
987
988 $curl->set_option('CURLOPT_USERAGENT', 'AnotherUserAgent/1.0');
989 $curl->call_apply_opt();
990 $this->assertTrue(in_array('User-Agent: AnotherUserAgent/1.0', $curl->header));
991 $this->assertFalse(in_array('User-Agent: Test/1.0', $curl->header));
992
993 $curl->set_option('CURLOPT_USERAGENT', 'AnotherUserAgent/1.1');
994 $options = $curl->get_options();
995 $curl->call_apply_opt($options);
996 $this->assertTrue(in_array('User-Agent: AnotherUserAgent/1.1', $curl->header));
997 $this->assertFalse(in_array('User-Agent: AnotherUserAgent/1.0', $curl->header));
998
999 $curl->unset_option('CURLOPT_USERAGENT');
1000 $curl->call_apply_opt();
1001 $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header));
9a1adda5
EL
1002
1003 // Finally, test it via exttests, to ensure the agent is sent properly.
1004 // Matching.
1005 $testurl = $this->getExternalTestFileUrl('/test_agent.php');
1006 $extcurl = new curl();
1007 $contents = $extcurl->get($testurl, array(), array('CURLOPT_USERAGENT' => 'AnotherUserAgent/1.2'));
1008 $response = $extcurl->getResponse();
1009 $this->assertSame('200 OK', reset($response));
1010 $this->assertSame(0, $extcurl->get_errno());
1011 $this->assertSame('OK', $contents);
1012 // Not matching.
1013 $contents = $extcurl->get($testurl, array(), array('CURLOPT_USERAGENT' => 'NonMatchingUserAgent/1.2'));
1014 $response = $extcurl->getResponse();
1015 $this->assertSame('200 OK', reset($response));
1016 $this->assertSame(0, $extcurl->get_errno());
1017 $this->assertSame('', $contents);
cbb7c6a9 1018 }
296ab1e2
JL
1019
1020 /**
1021 * Test file_rewrite_pluginfile_urls.
1022 */
1023 public function test_file_rewrite_pluginfile_urls() {
1024
1025 $syscontext = context_system::instance();
1026 $originaltext = 'Fake test with an image <img src="@@PLUGINFILE@@/image.png">';
1027
1028 // Do the rewrite.
1029 $finaltext = file_rewrite_pluginfile_urls($originaltext, 'pluginfile.php', $syscontext->id, 'user', 'private', 0);
1030 $this->assertContains("pluginfile.php", $finaltext);
1031
1032 // Now undo.
1033 $options = array('reverse' => true);
1034 $finaltext = file_rewrite_pluginfile_urls($finaltext, 'pluginfile.php', $syscontext->id, 'user', 'private', 0, $options);
1035
1036 // Compare the final text is the same that the original.
1037 $this->assertEquals($originaltext, $finaltext);
1038 }
46089705
JL
1039
1040 /**
1041 * Helpter function to create draft files
1042 *
1043 * @param array $filedata data for the file record (to not use defaults)
1044 * @return stored_file the stored file instance
1045 */
1046 public static function create_draft_file($filedata = array()) {
1047 global $USER;
1048
46089705
JL
1049 $fs = get_file_storage();
1050
1051 $filerecord = array(
1052 'component' => 'user',
1053 'filearea' => 'draft',
1054 'itemid' => isset($filedata['itemid']) ? $filedata['itemid'] : file_get_unused_draft_itemid(),
1055 'author' => isset($filedata['author']) ? $filedata['author'] : fullname($USER),
1056 'filepath' => isset($filedata['filepath']) ? $filedata['filepath'] : '/',
1057 'filename' => isset($filedata['filename']) ? $filedata['filename'] : 'file.txt',
1058 );
1059
1060 if (isset($filedata['contextid'])) {
1061 $filerecord['contextid'] = $filedata['contextid'];
1062 } else {
1063 $usercontext = context_user::instance($USER->id);
1064 $filerecord['contextid'] = $usercontext->id;
1065 }
1066 $source = isset($filedata['source']) ? $filedata['source'] : serialize((object)array('source' => 'From string'));
1067 $content = isset($filedata['content']) ? $filedata['content'] : 'some content here';
1068
1069 $file = $fs->create_file_from_string($filerecord, $content);
1070 $file->set_source($source);
1071
1072 return $file;
1073 }
1074
1075 /**
1076 * Test file_merge_files_from_draft_area_into_filearea
1077 */
1078 public function test_file_merge_files_from_draft_area_into_filearea() {
1079 global $USER, $CFG;
1080
1081 $this->resetAfterTest(true);
1082 $this->setAdminUser();
1083 $fs = get_file_storage();
1084 $usercontext = context_user::instance($USER->id);
1085
1086 // Create a draft file.
1087 $filename = 'data.txt';
1088 $filerecord = array(
1089 'filename' => $filename,
1090 );
1091 $file = self::create_draft_file($filerecord);
ce78e33a 1092 $draftitemid = $file->get_itemid();
46089705
JL
1093
1094 $maxbytes = $CFG->userquota;
1095 $maxareabytes = $CFG->userquota;
1096 $options = array('subdirs' => 1,
1097 'maxbytes' => $maxbytes,
1098 'maxfiles' => -1,
1099 'areamaxbytes' => $maxareabytes);
1100
1101 // Add new file.
ce78e33a 1102 file_merge_files_from_draft_area_into_filearea($draftitemid, $usercontext->id, 'user', 'private', 0, $options);
46089705
JL
1103
1104 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1105 // Directory and file.
1106 $this->assertCount(2, $files);
1107 $found = false;
1108 foreach ($files as $file) {
1109 if (!$file->is_directory()) {
1110 $found = true;
1111 $this->assertEquals($filename, $file->get_filename());
1112 $this->assertEquals('some content here', $file->get_content());
1113 }
1114 }
1115 $this->assertTrue($found);
1116
1117 // Add two more files.
1118 $filerecord = array(
ce78e33a 1119 'itemid' => $draftitemid,
46089705
JL
1120 'filename' => 'second.txt',
1121 );
1122 self::create_draft_file($filerecord);
1123 $filerecord = array(
ce78e33a 1124 'itemid' => $draftitemid,
46089705
JL
1125 'filename' => 'third.txt',
1126 );
1127 $file = self::create_draft_file($filerecord);
1128
1129 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $usercontext->id, 'user', 'private', 0, $options);
1130
1131 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1132 $this->assertCount(4, $files);
1133
1134 // Update contents of one file.
1135 $filerecord = array(
1136 'filename' => 'second.txt',
1137 'content' => 'new content',
1138 );
1139 $file = self::create_draft_file($filerecord);
1140 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $usercontext->id, 'user', 'private', 0, $options);
1141
1142 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1143 $this->assertCount(4, $files);
1144 $found = false;
1145 foreach ($files as $file) {
1146 if ($file->get_filename() == 'second.txt') {
1147 $found = true;
1148 $this->assertEquals('new content', $file->get_content());
1149 }
1150 }
1151 $this->assertTrue($found);
1152
1153 // Update author.
1154 // Set different author in the current file.
1155 foreach ($files as $file) {
1156 if ($file->get_filename() == 'second.txt') {
1157 $file->set_author('Nobody');
1158 }
1159 }
1160 $filerecord = array(
1161 'filename' => 'second.txt',
1162 );
1163 $file = self::create_draft_file($filerecord);
1164
1165 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $usercontext->id, 'user', 'private', 0, $options);
1166
1167 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1168 $this->assertCount(4, $files);
1169 $found = false;
1170 foreach ($files as $file) {
1171 if ($file->get_filename() == 'second.txt') {
1172 $found = true;
1173 $this->assertEquals(fullname($USER), $file->get_author());
1174 }
1175 }
1176 $this->assertTrue($found);
1177
1178 }
1179
1180 /**
1181 * Test max area bytes for file_merge_files_from_draft_area_into_filearea
1182 */
1183 public function test_file_merge_files_from_draft_area_into_filearea_max_area_bytes() {
1184 global $USER;
1185
1186 $this->resetAfterTest(true);
1187 $this->setAdminUser();
1188 $fs = get_file_storage();
1189
1190 $file = self::create_draft_file();
1191 $options = array('subdirs' => 1,
1192 'maxbytes' => 5,
1193 'maxfiles' => -1,
1194 'areamaxbytes' => 10);
1195
1196 // Add new file.
1197 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $file->get_contextid(), 'user', 'private', 0, $options);
1198 $usercontext = context_user::instance($USER->id);
1199 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1200 $this->assertCount(0, $files);
1201 }
1202
1203 /**
1204 * Test max file bytes for file_merge_files_from_draft_area_into_filearea
1205 */
1206 public function test_file_merge_files_from_draft_area_into_filearea_max_file_bytes() {
1207 global $USER;
1208
1209 $this->resetAfterTest(true);
c86189ae
AG
1210 // The admin has no restriction for max file uploads, so use a normal user.
1211 $user = $this->getDataGenerator()->create_user();
1212 $this->setUser($user);
46089705
JL
1213 $fs = get_file_storage();
1214
1215 $file = self::create_draft_file();
1216 $options = array('subdirs' => 1,
1217 'maxbytes' => 1,
1218 'maxfiles' => -1,
1219 'areamaxbytes' => 100);
1220
1221 // Add new file.
1222 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $file->get_contextid(), 'user', 'private', 0, $options);
1223 $usercontext = context_user::instance($USER->id);
1224 // Check we only get the base directory, not a new file.
1225 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1226 $this->assertCount(1, $files);
1227 $file = array_shift($files);
1228 $this->assertTrue($file->is_directory());
1229 }
1230
1231 /**
1232 * Test max file number for file_merge_files_from_draft_area_into_filearea
1233 */
1234 public function test_file_merge_files_from_draft_area_into_filearea_max_files() {
1235 global $USER;
1236
1237 $this->resetAfterTest(true);
1238 $this->setAdminUser();
1239 $fs = get_file_storage();
1240
1241 $file = self::create_draft_file();
1242 $options = array('subdirs' => 1,
1243 'maxbytes' => 1000,
1244 'maxfiles' => 0,
1245 'areamaxbytes' => 1000);
1246
1247 // Add new file.
1248 file_merge_files_from_draft_area_into_filearea($file->get_itemid(), $file->get_contextid(), 'user', 'private', 0, $options);
1249 $usercontext = context_user::instance($USER->id);
1250 // Check we only get the base directory, not a new file.
1251 $files = $fs->get_area_files($usercontext->id, 'user', 'private', 0);
1252 $this->assertCount(1, $files);
1253 $file = array_shift($files);
1254 $this->assertTrue($file->is_directory());
1255 }
02375710
JL
1256
1257 /**
1258 * Test file_get_draft_area_info.
1259 */
1260 public function test_file_get_draft_area_info() {
1261 global $USER;
1262
1263 $this->resetAfterTest(true);
1264 $this->setAdminUser();
1265 $fs = get_file_storage();
1266
1267 $filerecord = array(
1268 'filename' => 'one.txt',
1269 );
1270 $file = self::create_draft_file($filerecord);
1271 $size = $file->get_filesize();
1272 $draftitemid = $file->get_itemid();
1273 // Add another file.
1274 $filerecord = array(
1275 'itemid' => $draftitemid,
1276 'filename' => 'second.txt',
1277 );
1278 $file = self::create_draft_file($filerecord);
1279 $size += $file->get_filesize();
1280
1281 // Create directory.
1282 $usercontext = context_user::instance($USER->id);
1283 $dir = $fs->create_directory($usercontext->id, 'user', 'draft', $draftitemid, '/testsubdir/');
1284 // Add file to directory.
1285 $filerecord = array(
1286 'itemid' => $draftitemid,
1287 'filename' => 'third.txt',
1288 'filepath' => '/testsubdir/',
1289 );
1290 $file = self::create_draft_file($filerecord);
1291 $size += $file->get_filesize();
1292
1293 $fileinfo = file_get_draft_area_info($draftitemid);
1294 $this->assertEquals(3, $fileinfo['filecount']);
1295 $this->assertEquals($size, $fileinfo['filesize']);
bef201c7 1296 $this->assertEquals(1, $fileinfo['foldercount']); // Directory created.
02375710
JL
1297 $this->assertEquals($size, $fileinfo['filesize_without_references']);
1298
1299 // Now get files from just one folder.
1300 $fileinfo = file_get_draft_area_info($draftitemid, '/testsubdir/');
1301 $this->assertEquals(1, $fileinfo['filecount']);
1302 $this->assertEquals($file->get_filesize(), $fileinfo['filesize']);
1303 $this->assertEquals(0, $fileinfo['foldercount']); // No subdirectories inside the directory.
1304 $this->assertEquals($file->get_filesize(), $fileinfo['filesize_without_references']);
1305
1306 // Check we get the same results if we call file_get_file_area_info.
1307 $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'draft', $draftitemid);
1308 $this->assertEquals(3, $fileinfo['filecount']);
1309 $this->assertEquals($size, $fileinfo['filesize']);
bef201c7 1310 $this->assertEquals(1, $fileinfo['foldercount']); // Directory created.
02375710
JL
1311 $this->assertEquals($size, $fileinfo['filesize_without_references']);
1312 }
1313
f74ac6e7 1314 /**
02375710
JL
1315 * Test file_get_file_area_info.
1316 */
1317 public function test_file_get_file_area_info() {
1318 global $USER;
1319
1320 $this->resetAfterTest(true);
1321 $this->setAdminUser();
1322 $fs = get_file_storage();
1323
1324 $filerecord = array(
1325 'filename' => 'one.txt',
1326 );
1327 $file = self::create_draft_file($filerecord);
1328 $size = $file->get_filesize();
1329 $draftitemid = $file->get_itemid();
1330 // Add another file.
1331 $filerecord = array(
1332 'itemid' => $draftitemid,
1333 'filename' => 'second.txt',
1334 );
1335 $file = self::create_draft_file($filerecord);
1336 $size += $file->get_filesize();
1337
1338 // Create directory.
1339 $usercontext = context_user::instance($USER->id);
1340 $dir = $fs->create_directory($usercontext->id, 'user', 'draft', $draftitemid, '/testsubdir/');
1341 // Add file to directory.
1342 $filerecord = array(
1343 'itemid' => $draftitemid,
1344 'filename' => 'third.txt',
1345 'filepath' => '/testsubdir/',
1346 );
1347 $file = self::create_draft_file($filerecord);
1348 $size += $file->get_filesize();
1349
1350 // Add files to user private file area.
1351 $options = array('subdirs' => 1, 'maxfiles' => 3);
1352 file_merge_files_from_draft_area_into_filearea($draftitemid, $file->get_contextid(), 'user', 'private', 0, $options);
1353
1354 $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'private');
1355 $this->assertEquals(3, $fileinfo['filecount']);
1356 $this->assertEquals($size, $fileinfo['filesize']);
bef201c7 1357 $this->assertEquals(1, $fileinfo['foldercount']); // Directory created.
02375710
JL
1358 $this->assertEquals($size, $fileinfo['filesize_without_references']);
1359
1360 // Now get files from just one folder.
1361 $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'private', 0, '/testsubdir/');
1362 $this->assertEquals(1, $fileinfo['filecount']);
1363 $this->assertEquals($file->get_filesize(), $fileinfo['filesize']);
1364 $this->assertEquals(0, $fileinfo['foldercount']); // No subdirectories inside the directory.
1365 $this->assertEquals($file->get_filesize(), $fileinfo['filesize_without_references']);
1366 }
f3c2afd0
JD
1367
1368 /**
1369 * Test confirming that draft files not referenced in the editor text are removed.
1370 */
1371 public function test_file_remove_editor_orphaned_files() {
1372 global $USER, $CFG;
1373 $this->resetAfterTest(true);
1374 $this->setAdminUser();
1375
1376 // Create three draft files.
1377 $filerecord = ['filename' => 'file1.png'];
1378 $file = self::create_draft_file($filerecord);
1379 $draftitemid = $file->get_itemid();
1380
1381 $filerecord['itemid'] = $draftitemid;
1382
1383 $filerecord['filename'] = 'file2.png';
1384 self::create_draft_file($filerecord);
1385
1386 $filerecord['filename'] = 'file 3.png';
1387 self::create_draft_file($filerecord);
1388
1389 // Confirm the user drafts area lists 3 files.
1390 $fs = get_file_storage();
1391 $usercontext = context_user::instance($USER->id);
1392 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
1393 $this->assertCount(3, $draftfiles);
1394
1395 // Now, spoof some editor text content, referencing 2 of the files; one requiring name encoding, one not.
1396 $editor = [
1397 'itemid' => $draftitemid,
1398 'text' => '
1399 <img src="'.$CFG->wwwroot.'/draftfile.php/'.$usercontext->id.'/user/draft/'.$draftitemid.'/file%203.png" alt="">
1400 <img src="'.$CFG->wwwroot.'/draftfile.php/'.$usercontext->id.'/user/draft/'.$draftitemid.'/file1.png" alt="">'
1401 ];
1402
1403 // Run the remove orphaned drafts function and confirm that only the referenced files remain in the user drafts.
1404 $expected = ['file1.png', 'file 3.png']; // The drafts we expect will not be removed (are referenced in the online text).
1405 file_remove_editor_orphaned_files($editor);
1406 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
1407 $this->assertCount(2, $draftfiles);
1408 foreach ($draftfiles as $file) {
1409 $this->assertContains($file->get_filename(), $expected);
1410 }
1411 }
cbb7c6a9
DC
1412}
1413
1414/**
1415 * Test-specific class to allow easier testing of curl functions.
9a1adda5
EL
1416 *
1417 * @copyright 2015 Dave Cooper
cbb7c6a9
DC
1418 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1419 */
9a1adda5 1420class testable_curl extends curl {
cbb7c6a9 1421 /**
9a1adda5
EL
1422 * Accessor for private options array using reflection.
1423 *
1424 * @return array
cbb7c6a9
DC
1425 */
1426 public function get_options() {
9a1adda5
EL
1427 // Access to private property.
1428 $rp = new ReflectionProperty('curl', 'options');
1429 $rp->setAccessible(true);
1430 return $rp->getValue($this);
1431 }
1432
1433 /**
1434 * Setter for private options array using reflection.
1435 *
1436 * @param array $options
1437 */
1438 public function set_options($options) {
1439 // Access to private property.
1440 $rp = new ReflectionProperty('curl', 'options');
1441 $rp->setAccessible(true);
1442 $rp->setValue($this, $options);
cbb7c6a9
DC
1443 }
1444
1445 /**
9a1adda5 1446 * Setter for individual option.
cbb7c6a9
DC
1447 * @param string $option
1448 * @param string $value
1449 */
1450 public function set_option($option, $value) {
9a1adda5
EL
1451 $options = $this->get_options();
1452 $options[$option] = $value;
1453 $this->set_options($options);
cbb7c6a9
DC
1454 }
1455
1456 /**
1457 * Unsets an option on the curl object
1458 * @param string $option
1459 */
1460 public function unset_option($option) {
9a1adda5
EL
1461 $options = $this->get_options();
1462 unset($options[$option]);
1463 $this->set_options($options);
cbb7c6a9
DC
1464 }
1465
1466 /**
9a1adda5 1467 * Wrapper to access the private curl::apply_opt() method using reflection.
cbb7c6a9
DC
1468 *
1469 * @param array $options
1470 * @return resource The curl handle
1471 */
1472 public function call_apply_opt($options = null) {
9a1adda5
EL
1473 // Access to private method.
1474 $rm = new ReflectionMethod('curl', 'apply_opt');
1475 $rm->setAccessible(true);
cbb7c6a9 1476 $ch = curl_init();
9a1adda5 1477 return $rm->invoke($this, $ch, $options);
cbb7c6a9 1478 }
a3d5830a 1479}