Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 
17
namespace core;
18
 
19
use file_archive;
20
use file_progress;
21
use zip_archive;
22
 
23
defined('MOODLE_INTERNAL') || die();
24
 
25
global $CFG;
26
require_once($CFG->libdir . '/filestorage/file_progress.php');
27
 
28
/**
29
 * Unit tests for /lib/filestorage/zip_packer.php and zip_archive.php
30
 *
31
 * @package   core
32
 * @category  test
33
 * @copyright 2012 Petr Skoda
34
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class zip_packer_test extends \advanced_testcase implements file_progress {
37
    protected $testfile;
38
    protected $files;
39
 
40
    /**
41
     * @var array Progress information passed to the progress reporter
42
     */
43
    protected $progress;
44
 
45
    protected function setUp(): void {
46
        parent::setUp();
47
 
48
        $this->testfile = __DIR__.'/fixtures/test.txt';
49
 
50
        $fs = get_file_storage();
51
        $context = \context_system::instance();
52
        if (!$file = $fs->get_file($context->id, 'phpunit', 'data', 0, '/', 'test.txt')) {
53
            $file = $fs->create_file_from_pathname(
54
                array('contextid'=>$context->id, 'component'=>'phpunit', 'filearea'=>'data', 'itemid'=>0, 'filepath'=>'/', 'filename'=>'test.txt'),
55
                $this->testfile);
56
        }
57
 
58
        $this->files = array(
59
            'test.test' => $this->testfile,
60
            'testíček.txt' => $this->testfile,
61
            'Prüfung.txt' => $this->testfile,
62
            '测试.txt' => $this->testfile,
63
            '試験.txt' => $this->testfile,
64
            'Žluťoučký/Koníček.txt' => $file,
65
        );
66
    }
67
 
11 efrain 68
    public function test_get_packer(): void {
1 efrain 69
        $this->resetAfterTest(false);
70
        $packer = get_file_packer();
71
        $this->assertInstanceOf('zip_packer', $packer);
72
 
73
        $packer = get_file_packer('application/zip');
74
        $this->assertInstanceOf('zip_packer', $packer);
75
    }
76
 
77
    /**
78
     * @depends test_get_packer
79
     */
11 efrain 80
    public function test_list_files(): void {
1 efrain 81
        $this->resetAfterTest(false);
82
 
83
        $files = array(
84
            __DIR__.'/fixtures/test_moodle_22.zip',
85
            __DIR__.'/fixtures/test_moodle.zip',
86
            __DIR__.'/fixtures/test_tc_8.zip',
87
            __DIR__.'/fixtures/test_7zip_927.zip',
88
            __DIR__.'/fixtures/test_winzip_165.zip',
89
            __DIR__.'/fixtures/test_winrar_421.zip',
90
            __DIR__.'/fixtures/test_thumbsdb.zip',
91
        );
92
 
93
        if (function_exists('normalizer_normalize')) {
94
            // Unfortunately there is no way to standardise UTF-8 strings without INTL extension.
95
            $files[] = __DIR__.'/fixtures/test_infozip_3.zip';
96
            $files[] = __DIR__.'/fixtures/test_osx_1074.zip';
97
            $files[] = __DIR__.'/fixtures/test_osx_compress.zip';
98
        }
99
 
100
        $packer = get_file_packer('application/zip');
101
 
102
        foreach ($files as $archive) {
103
            $archivefiles = $packer->list_files($archive);
104
            $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
105
            $this->assertTrue(count($this->files) === count($archivefiles) or count($this->files) === count($archivefiles) - 1); // Some zippers create empty dirs.
106
            foreach ($archivefiles as $file) {
107
                if ($file->pathname === 'Žluťoučký/') {
108
                    // Some zippers create empty dirs.
109
                    continue;
110
                }
111
                $this->assertArrayHasKey($file->pathname, $this->files, "File $file->pathname not extracted properly: ".basename($archive).' ');
112
            }
113
        }
114
 
115
        // Windows packer supports only DOS encoding.
116
        $archive = __DIR__.'/fixtures/test_win8_de.zip';
117
        $archivefiles = $packer->list_files($archive);
118
        $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
119
        $this->assertEquals(2, count($archivefiles));
120
        foreach ($archivefiles as $file) {
121
            $this->assertTrue($file->pathname === 'Prüfung.txt' or $file->pathname === 'test.test');
122
        }
123
 
124
        $zip_archive = new zip_archive();
125
        $zip_archive->open(__DIR__.'/fixtures/test_win8_cz.zip', file_archive::OPEN, 'cp852');
126
        $archivefiles = $zip_archive->list_files();
127
        $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
128
        $this->assertEquals(3, count($archivefiles));
129
        foreach ($archivefiles as $file) {
130
            $this->assertTrue($file->pathname === 'Žluťoučký/Koníček.txt' or $file->pathname === 'testíček.txt' or $file->pathname === 'test.test');
131
        }
132
        $zip_archive->close();
133
 
134
        // Empty archive extraction.
135
        $archive = __DIR__.'/fixtures/empty.zip';
136
        $archivefiles = $packer->list_files($archive);
137
        $this->assertSame(array(), $archivefiles);
138
    }
139
 
140
    /**
141
     * @depends test_list_files
142
     */
11 efrain 143
    public function test_archive_to_pathname(): void {
1 efrain 144
        global $CFG;
145
 
146
        $this->resetAfterTest(false);
147
 
148
        $packer = get_file_packer('application/zip');
149
        $archive = "$CFG->tempdir/archive.zip";
150
 
151
        $this->assertFileDoesNotExist($archive);
152
        $result = $packer->archive_to_pathname($this->files, $archive);
153
        $this->assertTrue($result);
154
        $this->assertFileExists($archive);
155
 
156
        $archivefiles = $packer->list_files($archive);
157
        $this->assertTrue(is_array($archivefiles));
158
        $this->assertEquals(count($this->files), count($archivefiles));
159
        foreach ($archivefiles as $file) {
160
            $this->assertArrayHasKey($file->pathname, $this->files);
161
        }
162
 
163
        // Test invalid files parameter.
164
        $archive = "$CFG->tempdir/archive2.zip";
165
        $this->assertFileDoesNotExist($archive);
166
 
167
        $this->assertFileDoesNotExist(__DIR__.'/xx/yy/ee.txt');
168
        $files = array('xtest.txt'=>__DIR__.'/xx/yy/ee.txt');
169
 
170
        $result = $packer->archive_to_pathname($files, $archive, false);
171
        $this->assertFalse($result);
172
        $this->assertDebuggingCalled();
173
        $this->assertFileDoesNotExist($archive);
174
 
175
        $result = $packer->archive_to_pathname($files, $archive);
176
        $this->assertTrue($result);
177
        $this->assertFileExists($archive);
178
        $this->assertDebuggingCalled();
179
        $archivefiles = $packer->list_files($archive);
180
        $this->assertSame(array(), $archivefiles);
181
        unlink($archive);
182
 
183
        $this->assertFileDoesNotExist(__DIR__.'/xx/yy/ee.txt');
184
        $this->assertFileExists(__DIR__.'/fixtures/test.txt');
185
        $files = array('xtest.txt'=>__DIR__.'/xx/yy/ee.txt', 'test.txt'=>__DIR__.'/fixtures/test.txt', 'ytest.txt'=>__DIR__.'/xx/yy/yy.txt');
186
        $result = $packer->archive_to_pathname($files, $archive);
187
        $this->assertTrue($result);
188
        $this->assertFileExists($archive);
189
        $archivefiles = $packer->list_files($archive);
190
        $this->assertCount(1, $archivefiles);
191
        $this->assertEquals('test.txt', $archivefiles[0]->pathname);
192
        $dms = $this->getDebuggingMessages();
193
        $this->assertCount(2, $dms);
194
        $this->resetDebugging();
195
        unlink($archive);
196
    }
197
 
198
    /**
199
     * @depends test_archive_to_pathname
200
     */
11 efrain 201
    public function test_archive_to_storage(): void {
1 efrain 202
        $this->resetAfterTest(false);
203
 
204
        $packer = get_file_packer('application/zip');
205
        $fs = get_file_storage();
206
        $context = \context_system::instance();
207
 
208
        $this->assertFalse($fs->file_exists($context->id, 'phpunit', 'test', 0, '/', 'archive.zip'));
209
        $result = $packer->archive_to_storage($this->files, $context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
210
        $this->assertInstanceOf('stored_file', $result);
211
        $this->assertTrue($fs->file_exists($context->id, 'phpunit', 'test', 0, '/', 'archive.zip'));
212
 
213
        $archivefiles = $result->list_files($packer);
214
        $this->assertTrue(is_array($archivefiles));
215
        $this->assertEquals(count($this->files), count($archivefiles));
216
        foreach ($archivefiles as $file) {
217
            $this->assertArrayHasKey($file->pathname, $this->files);
218
        }
219
    }
220
 
221
    /**
222
     * @depends test_archive_to_storage
223
     */
11 efrain 224
    public function test_extract_to_pathname(): void {
1 efrain 225
        global $CFG;
226
 
227
        $this->resetAfterTest(false);
228
 
229
        $packer = get_file_packer('application/zip');
230
        $fs = get_file_storage();
231
        $context = \context_system::instance();
232
 
233
        $target = "$CFG->tempdir/test/";
234
        $testcontent = file_get_contents($this->testfile);
235
 
236
        @mkdir($target, $CFG->directorypermissions);
237
        $this->assertTrue(is_dir($target));
238
 
239
        $archive = "$CFG->tempdir/archive.zip";
240
        $this->assertFileExists($archive);
241
        $result = $packer->extract_to_pathname($archive, $target);
242
        $this->assertTrue(is_array($result));
243
        $this->assertEquals(count($this->files), count($result));
244
        foreach ($this->files as $file => $unused) {
245
            $this->assertTrue($result[$file]);
246
            $this->assertFileExists($target.$file);
247
            $this->assertSame($testcontent, file_get_contents($target.$file));
248
        }
249
 
250
        $archive = $fs->get_file($context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
251
        $this->assertNotEmpty($archive);
252
        $result = $packer->extract_to_pathname($archive, $target);
253
        $this->assertTrue(is_array($result));
254
        $this->assertEquals(count($this->files), count($result));
255
        foreach ($this->files as $file => $unused) {
256
            $this->assertTrue($result[$file]);
257
            $this->assertFileExists($target.$file);
258
            $this->assertSame($testcontent, file_get_contents($target.$file));
259
        }
260
    }
261
 
262
    /**
263
     * Test functionality of {@see zip_packer} for entries with folders ending with dots.
264
     *
265
     * @link https://bugs.php.net/bug.php?id=77214
266
     */
11 efrain 267
    public function test_zip_entry_path_having_folder_ending_with_dot(): void {
1 efrain 268
        global $CFG;
269
 
270
        $this->resetAfterTest(false);
271
 
272
        $packer = get_file_packer('application/zip');
273
        $tmp = make_request_directory();
274
        $now = time();
275
 
276
        // Create a test archive containing a folder ending with dot.
277
        $zippath = $tmp . '/test_archive.zip';
278
        $zipcontents = [
279
            'HOW.TO' => ['Just run tests.'],
280
            'README.' => ['This is a test ZIP file'],
281
            './Current time' => [$now],
282
            'Data/sub1./sub2/1221' => ['1221'],
283
            'Data/sub1./sub2./Příliš žluťoučký kůň úpěl Ďábelské Ódy.txt' => [''],
284
        ];
285
 
286
        if ($CFG->ostype === 'WINDOWS') {
287
            // File names cannot end with dots on Windows and trailing dots are replaced with underscore.
288
            $filenamemap = [
289
                'HOW.TO' => 'HOW.TO',
290
                'README.' => 'README_',
291
                './Current time' => 'Current time',
292
                'Data/sub1./sub2/1221' => 'Data/sub1_/sub2/1221',
293
                'Data/sub1./sub2./Příliš žluťoučký kůň úpěl Ďábelské Ódy.txt' =>
294
                    'Data/sub1_/sub2_/Příliš žluťoučký kůň úpěl Ďábelské Ódy.txt',
295
            ];
296
 
297
        } else {
298
            $filenamemap = [
299
                'HOW.TO' => 'HOW.TO',
300
                'README.' => 'README.',
301
                './Current time' => 'Current time',
302
                'Data/sub1./sub2/1221' => 'Data/sub1./sub2/1221',
303
                'Data/sub1./sub2./Příliš žluťoučký kůň úpěl Ďábelské Ódy.txt' =>
304
                    'Data/sub1./sub2./Příliš žluťoučký kůň úpěl Ďábelské Ódy.txt',
305
            ];
306
        }
307
 
308
        // Check that the archive can be created.
309
        $result = $packer->archive_to_pathname($zipcontents, $zippath, false);
310
        $this->assertTrue($result);
311
 
312
        // Check list of files.
313
        $listfiles = $packer->list_files($zippath);
314
        $this->assertEquals(count($zipcontents), count($listfiles));
315
 
316
        foreach ($listfiles as $fileinfo) {
317
            $this->assertSame($fileinfo->pathname, $fileinfo->original_pathname);
318
            $this->assertArrayHasKey($fileinfo->pathname, $zipcontents);
319
        }
320
 
321
        // Check actual extracting.
322
        $targetpath = $tmp . '/target';
323
        check_dir_exists($targetpath);
324
        $result = $packer->extract_to_pathname($zippath, $targetpath, null, null, true);
325
 
326
        $this->assertTrue($result);
327
 
328
        foreach ($zipcontents as $filename => $filecontents) {
329
            $filecontents = reset($filecontents);
330
            $this->assertTrue(is_readable($targetpath . '/' . $filenamemap[$filename]));
331
            $this->assertEquals($filecontents, file_get_contents($targetpath . '/' . $filenamemap[$filename]));
332
        }
333
    }
334
 
335
    /**
336
     * @depends test_archive_to_storage
337
     */
11 efrain 338
    public function test_extract_to_pathname_onlyfiles(): void {
1 efrain 339
        global $CFG;
340
 
341
        $this->resetAfterTest(false);
342
 
343
        $packer = get_file_packer('application/zip');
344
        $fs = get_file_storage();
345
        $context = \context_system::instance();
346
 
347
        $target = "$CFG->tempdir/onlyfiles/";
348
        $testcontent = file_get_contents($this->testfile);
349
 
350
        @mkdir($target, $CFG->directorypermissions);
351
        $this->assertTrue(is_dir($target));
352
 
353
        $onlyfiles = array('test', 'test.test', 'Žluťoučký/Koníček.txt', 'Idontexist');
354
        $willbeextracted = array_intersect(array_keys($this->files), $onlyfiles);
355
        $donotextract = array_diff(array_keys($this->files), $onlyfiles);
356
 
357
        $archive = "$CFG->tempdir/archive.zip";
358
        $this->assertFileExists($archive);
359
        $result = $packer->extract_to_pathname($archive, $target, $onlyfiles);
360
        $this->assertTrue(is_array($result));
361
        $this->assertEquals(count($willbeextracted), count($result));
362
 
363
        foreach ($willbeextracted as $file) {
364
            $this->assertTrue($result[$file]);
365
            $this->assertFileExists($target.$file);
366
            $this->assertSame($testcontent, file_get_contents($target.$file));
367
        }
368
        foreach ($donotextract as $file) {
369
            $this->assertFalse(isset($result[$file]));
370
            $this->assertFileDoesNotExist($target.$file);
371
        }
372
 
373
    }
374
 
375
    /**
376
     * @depends test_archive_to_storage
377
     */
11 efrain 378
    public function test_extract_to_pathname_returnvalue_successful(): void {
1 efrain 379
        global $CFG;
380
 
381
        $this->resetAfterTest(false);
382
 
383
        $packer = get_file_packer('application/zip');
384
 
385
        $target = make_request_directory();
386
 
387
        $archive = "$CFG->tempdir/archive.zip";
388
        $this->assertFileExists($archive);
389
        $result = $packer->extract_to_pathname($archive, $target, null, null, true);
390
        $this->assertTrue($result);
391
    }
392
 
393
    /**
394
     * @depends test_archive_to_storage
395
     */
11 efrain 396
    public function test_extract_to_pathname_returnvalue_failure(): void {
1 efrain 397
        global $CFG;
398
 
399
        $this->resetAfterTest(false);
400
 
401
        $packer = get_file_packer('application/zip');
402
 
403
        $target = make_request_directory();
404
 
405
        $archive = "$CFG->tempdir/noarchive.zip";
406
        $result = $packer->extract_to_pathname($archive, $target, null, null, true);
407
        $this->assertFalse($result);
408
    }
409
 
410
    /**
411
     * @depends test_archive_to_storage
412
     */
11 efrain 413
    public function test_extract_to_storage(): void {
1 efrain 414
        global $CFG;
415
 
416
        $this->resetAfterTest(false);
417
 
418
        $packer = get_file_packer('application/zip');
419
        $fs = get_file_storage();
420
        $context = \context_system::instance();
421
 
422
        $testcontent = file_get_contents($this->testfile);
423
 
424
        $archive = $fs->get_file($context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
425
        $this->assertNotEmpty($archive);
426
        $result = $packer->extract_to_storage($archive, $context->id, 'phpunit', 'target', 0, '/');
427
        $this->assertTrue(is_array($result));
428
        $this->assertEquals(count($this->files), count($result));
429
        foreach ($this->files as $file => $unused) {
430
            $this->assertTrue($result[$file]);
431
            $stored_file = $fs->get_file_by_hash(sha1("/$context->id/phpunit/target/0/$file"));
432
            $this->assertInstanceOf('stored_file', $stored_file);
433
            $this->assertSame($testcontent, $stored_file->get_content());
434
        }
435
 
436
        $archive = "$CFG->tempdir/archive.zip";
437
        $this->assertFileExists($archive);
438
        $result = $packer->extract_to_storage($archive, $context->id, 'phpunit', 'target', 0, '/');
439
        $this->assertTrue(is_array($result));
440
        $this->assertEquals(count($this->files), count($result));
441
        foreach ($this->files as $file => $unused) {
442
            $this->assertTrue($result[$file]);
443
            $stored_file = $fs->get_file_by_hash(sha1("/$context->id/phpunit/target/0/$file"));
444
            $this->assertInstanceOf('stored_file', $stored_file);
445
            $this->assertSame($testcontent, $stored_file->get_content());
446
        }
447
        unlink($archive);
448
    }
449
 
450
    /**
451
     * @depends test_extract_to_storage
452
     */
11 efrain 453
    public function test_add_files(): void {
1 efrain 454
        global $CFG;
455
 
456
        $this->resetAfterTest(false);
457
 
458
        $packer = get_file_packer('application/zip');
459
        $archive = "$CFG->tempdir/archive.zip";
460
 
461
        $this->assertFileDoesNotExist($archive);
462
        $packer->archive_to_pathname(array(), $archive);
463
        $this->assertFileExists($archive);
464
 
465
        $zip_archive = new zip_archive();
466
        $zip_archive->open($archive, file_archive::OPEN);
467
        $this->assertEquals(0, $zip_archive->count());
468
 
469
        $zip_archive->add_file_from_string('test.txt', 'test');
470
        $zip_archive->close();
471
        $zip_archive->open($archive, file_archive::OPEN);
472
        $this->assertEquals(1, $zip_archive->count());
473
 
474
        $zip_archive->add_directory('test2');
475
        $zip_archive->close();
476
        $zip_archive->open($archive, file_archive::OPEN);
477
        $files = $zip_archive->list_files();
478
        $this->assertCount(2, $files);
479
        $this->assertEquals('test.txt', $files[0]->pathname);
480
        $this->assertEquals('test2/', $files[1]->pathname);
481
 
482
        $result = $zip_archive->add_file_from_pathname('test.txt', __DIR__.'/nonexistent/file.txt');
483
        $this->assertFalse($result);
484
        $zip_archive->close();
485
        $zip_archive->open($archive, file_archive::OPEN);
486
        $this->assertEquals(2, $zip_archive->count());
487
        $zip_archive->close();
488
 
489
        unlink($archive);
490
    }
491
 
11 efrain 492
    public function test_close_archive(): void {
1 efrain 493
        global $CFG;
494
 
495
        $this->resetAfterTest(true);
496
 
497
        $archive = "$CFG->tempdir/archive.zip";
498
        $textfile = "$CFG->tempdir/textfile.txt";
499
        touch($textfile);
500
 
501
        $this->assertFileDoesNotExist($archive);
502
        $this->assertFileExists($textfile);
503
 
504
        // Create archive and close it without files.
505
        // (returns true, without any warning).
506
        $zip_archive = new zip_archive();
507
        $result = $zip_archive->open($archive, file_archive::CREATE);
508
        $this->assertTrue($result);
509
        $result = $zip_archive->close();
510
        $this->assertTrue($result);
511
        unlink($archive);
512
 
513
        // Create archive and close it with files.
514
        // (returns true, without any warning).
515
        $zip_archive = new zip_archive();
516
        $result = $zip_archive->open($archive, file_archive::CREATE);
517
        $this->assertTrue($result);
518
        $result = $zip_archive->add_file_from_string('test.txt', 'test');
519
        $this->assertTrue($result);
520
        $result = $zip_archive->add_file_from_pathname('test2.txt', $textfile);
521
        $result = $zip_archive->close();
522
        $this->assertTrue($result);
523
        unlink($archive);
524
 
525
        // Create archive and close if forcing error.
526
        // (returns true for old PHP versions and
527
        // false with warnings for new PHP versions). MDL-51863.
528
        $zip_archive = new zip_archive();
529
        $result = $zip_archive->open($archive, file_archive::CREATE);
530
        $this->assertTrue($result);
531
        $result = $zip_archive->add_file_from_string('test.txt', 'test');
532
        $this->assertTrue($result);
533
        $result = $zip_archive->add_file_from_pathname('test2.txt', $textfile);
534
        $this->assertTrue($result);
535
        // Delete the file before closing does force close() to fail.
536
        unlink($textfile);
537
        // Behavior is different between old PHP versions and new ones. Let's detect it.
538
        $result = false;
539
        try {
540
            // Old PHP versions were not printing any warning.
541
            $result = $zip_archive->close();
542
        } catch (\Exception $e) {
543
            // New PHP versions print PHP Warning.
544
            $this->assertInstanceOf('PHPUnit\Framework\Error\Warning', $e);
545
            $this->assertStringContainsString('ZipArchive::close', $e->getMessage());
546
        }
547
        // This is crazy, but it shows how some PHP versions do return true.
548
        try {
549
            // And some PHP versions do return correctly false (5.4.25, 5.6.14...)
550
            $this->assertFalse($result);
551
        } catch (\Exception $e) {
552
            // But others do insist into returning true (5.6.13...). Only can accept them.
553
            $this->assertInstanceOf('PHPUnit\Framework\ExpectationFailedException', $e);
554
            $this->assertTrue($result);
555
        }
556
        $this->assertFileDoesNotExist($archive);
557
    }
558
 
559
    /**
560
     * @depends test_add_files
561
     */
11 efrain 562
    public function test_open_archive(): void {
1 efrain 563
        global $CFG;
564
 
565
        $this->resetAfterTest(true);
566
 
567
        $archive = "$CFG->tempdir/archive.zip";
568
 
569
        $this->assertFileDoesNotExist($archive);
570
 
571
        $zip_archive = new zip_archive();
572
        $result = $zip_archive->open($archive, file_archive::OPEN);
573
        $this->assertFalse($result);
574
        $this->assertDebuggingCalled();
575
 
576
        $zip_archive = new zip_archive();
577
        $result = $zip_archive->open($archive, file_archive::CREATE);
578
        $this->assertTrue($result);
579
        $zip_archive->add_file_from_string('test.txt', 'test');
580
        $zip_archive->close();
581
        $zip_archive->open($archive, file_archive::OPEN);
582
        $this->assertEquals(1, $zip_archive->count());
583
 
584
        $zip_archive = new zip_archive();
585
        $result = $zip_archive->open($archive, file_archive::OVERWRITE);
586
        $this->assertTrue($result);
587
        $zip_archive->add_file_from_string('test2.txt', 'test');
588
        $zip_archive->close();
589
        $zip_archive->open($archive, file_archive::OPEN);
590
        $this->assertEquals(1, $zip_archive->count());
591
        $zip_archive->close();
592
 
593
        unlink($archive);
594
        $zip_archive = new zip_archive();
595
        $result = $zip_archive->open($archive, file_archive::OVERWRITE);
596
        $this->assertTrue($result);
597
        $zip_archive->add_file_from_string('test2.txt', 'test');
598
        $zip_archive->close();
599
        $zip_archive->open($archive, file_archive::OPEN);
600
        $this->assertEquals(1, $zip_archive->count());
601
        $zip_archive->close();
602
 
603
        unlink($archive);
604
    }
605
 
606
    /**
607
     * Test opening an encrypted archive
608
     */
11 efrain 609
    public function test_open_encrypted_archive(): void {
1 efrain 610
        $this->resetAfterTest();
611
 
612
        // The archive contains a single encrypted "hello.txt" file.
613
        $archive = __DIR__ . '/fixtures/passwordis1.zip';
614
 
615
        /** @var \zip_packer $packer */
616
        $packer = get_file_packer('application/zip');
617
        $result = $packer->extract_to_pathname($archive, make_temp_directory('zip'));
618
 
619
        $this->assertIsArray($result);
620
        $this->assertArrayHasKey('hello.txt', $result);
621
        $this->assertEquals('Can not read file from zip archive', $result['hello.txt']);
622
    }
623
 
624
    /**
625
     * Tests the progress reporting.
626
     */
11 efrain 627
    public function test_file_progress(): void {
1 efrain 628
        global $CFG;
629
 
630
        // Set up.
631
        $this->resetAfterTest(true);
632
        $packer = get_file_packer('application/zip');
633
        $archive = "$CFG->tempdir/archive.zip";
634
        $context = \context_system::instance();
635
 
636
        // Archive to pathname.
637
        $this->progress = array();
638
        $result = $packer->archive_to_pathname($this->files, $archive, true, $this);
639
        $this->assertTrue($result);
640
        // Should send progress at least once per file.
641
        $this->assertTrue(count($this->progress) >= count($this->files));
642
        // Each progress will be indeterminate.
643
        $this->assertEquals(
644
                array(file_progress::INDETERMINATE, file_progress::INDETERMINATE),
645
                $this->progress[0]);
646
 
647
        // Archive to pathname using entire folder and subfolder instead of file list.
648
        unlink($archive);
649
        $folder = make_temp_directory('zip_packer_progress');
650
        file_put_contents($folder . '/test1.txt', 'hello');
651
        $subfolder = $folder . '/sub';
652
        check_dir_exists($subfolder);
653
        file_put_contents($subfolder . '/test2.txt', 'world');
654
        file_put_contents($subfolder . '/test3.txt', 'and');
655
        file_put_contents($subfolder . '/test4.txt', 'other');
656
        file_put_contents($subfolder . '/test5.txt', 'worlds');
657
        $this->progress = array();
658
        $result = $packer->archive_to_pathname(array('' => $folder), $archive, true, $this);
659
        $this->assertTrue($result);
660
        // Should send progress at least once per file.
661
        $this->assertTrue(count($this->progress) >= 5);
662
 
663
        // Archive to storage.
664
        $this->progress = array();
665
        $archivefile = $packer->archive_to_storage($this->files, $context->id,
666
                'phpunit', 'test', 0, '/', 'archive.zip', null, true, $this);
667
        $this->assertInstanceOf('stored_file', $archivefile);
668
        $this->assertTrue(count($this->progress) >= count($this->files));
669
        $this->assertEquals(
670
                array(file_progress::INDETERMINATE, file_progress::INDETERMINATE),
671
                $this->progress[0]);
672
 
673
        // Extract to pathname.
674
        $this->progress = array();
675
        $target = "$CFG->tempdir/test/";
676
        check_dir_exists($target);
677
        $result = $packer->extract_to_pathname($archive, $target, null, $this);
678
        remove_dir($target);
679
        $this->assertEquals(count($this->files), count($result));
680
        $this->assertTrue(count($this->progress) >= count($this->files));
681
        $this->check_progress_toward_max();
682
 
683
        // Extract to storage (from storage).
684
        $this->progress = array();
685
        $result = $packer->extract_to_storage($archivefile, $context->id,
686
                'phpunit', 'target', 0, '/', null, $this);
687
        $this->assertEquals(count($this->files), count($result));
688
        $this->assertTrue(count($this->progress) >= count($this->files));
689
        $this->check_progress_toward_max();
690
 
691
        // Extract to storage (from path).
692
        $this->progress = array();
693
        $result = $packer->extract_to_storage($archive, $context->id,
694
                'phpunit', 'target', 0, '/', null, $this);
695
        $this->assertEquals(count($this->files), count($result));
696
        $this->assertTrue(count($this->progress) >= count($this->files));
697
        $this->check_progress_toward_max();
698
 
699
        // Wipe created disk file.
700
        unlink($archive);
701
    }
702
 
703
    /**
704
     * Checks that progress reported is numeric rather than indeterminate,
705
     * and follows the progress reporting rules.
706
     */
707
    private function check_progress_toward_max() {
708
        $lastvalue = -1;
709
        foreach ($this->progress as $progressitem) {
710
            list($value, $max) = $progressitem;
711
            $this->assertNotEquals(file_progress::INDETERMINATE, $max);
712
            $this->assertTrue($value <= $max);
713
            $this->assertTrue($value >= $lastvalue);
714
            $lastvalue = $value;
715
        }
716
    }
717
 
718
    /**
719
     * Handles file_progress interface.
720
     *
721
     * @param int $progress
722
     * @param int $max
723
     */
724
    public function progress($progress = file_progress::INDETERMINATE, $max = file_progress::INDETERMINATE) {
725
        $this->progress[] = array($progress, $max);
726
    }
727
}