Completed
Push — master ( b92b03...f52886 )
by Orkhan
02:51
created

ZipContent::contains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Orkhanahmadov\ZipValidator\Rules;
4
5
use Illuminate\Contracts\Validation\Rule;
6
use Illuminate\Http\UploadedFile;
7
use Illuminate\Support\Collection;
8
use Orkhanahmadov\ZipValidator\Exceptions\ZipException;
9
use ZipArchive;
10
11
class ZipContent implements Rule
12
{
13
    /**
14
     * @var ZipArchive
15
     */
16
    private $zip;
17
    /**
18
     * @var Collection
19
     */
20
    private $files;
21
    /**
22
     * @var Collection
23
     */
24
    private $failedFiles;
25
26
    /**
27
     * Create a new rule instance.
28
     *
29
     * @param array|string $files
30
     */
31
    public function __construct($files)
32
    {
33
        $this->zip = new ZipArchive();
34
        $this->files = is_array($files) ? collect($files) : collect(func_get_args());
35
    }
36
37
    /**
38
     * Determine if the validation rule passes.
39
     *
40
     * @param string $attribute
41
     * @param UploadedFile $zip
42
     * @return bool
43
     */
44
    public function passes($attribute, $zip): bool
45
    {
46
        $content = $this->readContent($zip);
47
48
        $this->failedFiles = $this->files->reject(function ($value, $key) use ($content) {
49
            $namesInsideZip = $content->pluck('name');
50
51
            if (! is_int($value)) {
52
                return $this->contains($namesInsideZip, $value);
53
            }
54
55
            $matchingName = $this->contains($namesInsideZip, $key);
56
            if (! $matchingName) {
57
                return false;
58
            }
59
60
            return $content->firstWhere('name', $matchingName)['size'] <= $value;
61
        });
62
63
        return ! $this->failedFiles->count();
64
    }
65
66
    /**
67
     * Get the validation error message.
68
     *
69
     * @return string
70
     */
71
    public function message(): string
72
    {
73
        return __('zipValidator::messages.failed', [
74
            'files' => $this->failedFiles->implode(', '),
75
        ]);
76
    }
77
78
    /**
79
     * Reads ZIP file content and returns collection with result.
80
     *
81
     * @param UploadedFile $value
82
     *
83
     * @return Collection
84
     */
85
    private function readContent(UploadedFile $value): Collection
86
    {
87
        $zipOpen = $this->zip->open($value->path());
88
        throw_unless($zipOpen === true, new ZipException($zipOpen));
89
90
        $content = collect();
91
        for ($i = 0; $i < $this->zip->count(); $i++) {
0 ignored issues
show
Bug introduced by
The method count() does not exist on ZipArchive. ( Ignorable by Annotation )

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

91
        for ($i = 0; $i < $this->zip->/** @scrutinizer ignore-call */ count(); $i++) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
92
            $content->add($this->zip->statIndex($i));
93
        }
94
95
        $this->zip->close();
96
97
        return $content;
98
    }
99
100
    /**
101
     * Checks if file name exists in ZIP file. Returns matching file name, null otherwise.
102
     *
103
     * @param Collection $namesInsideZip
104
     * @param string $search
105
     *
106
     * @return string|null
107
     */
108
    private function contains(Collection $namesInsideZip, string $search): ?string
109
    {
110
        $options = explode('|', $search);
111
112
        return $namesInsideZip->first(function ($name) use ($options) {
113
            return in_array($name, $options);
114
        });
115
    }
116
}
117