Passed
Push — master ( f52886...be0244 )
by Orkhan
02:35
created

ZipContent::validate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 3
nc 3
nop 3
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
        $zipContent = $this->readContent($zip);
47
48
        $this->failedFiles = $this->files->reject(function ($value, $key) use ($zipContent) {
49
            return $this->validate($zipContent, $value, $key);
50
        });
51
52
        return $this->failedFiles->count() === 0;
53
    }
54
55
    /**
56
     * @param Collection $zipContent
57
     * @param string|int $value
58
     * @param string|int $key
59
     *
60
     * @return bool
61
     */
62
    public function validate(Collection $zipContent, $value, $key): bool
63
    {
64
        if (! is_int($value)) {
65
            return (bool) $this->contains($zipContent->pluck('name'), $value);
66
        }
67
68
        $existingName = $this->contains($zipContent->pluck('name'), $key);
69
        if (! $existingName) {
70
            return false;
71
        }
72
73
        return $zipContent->firstWhere('name', $existingName)['size'] <= $value;
74
    }
75
76
    /**
77
     * Checks if file name exists in ZIP file. Returns matching file name, null otherwise.
78
     *
79
     * @param Collection $names
80
     * @param string $search
81
     *
82
     * @return string|null
83
     */
84
    public function contains(Collection $names, string $search): ?string
85
    {
86
        $options = explode('|', $search);
87
88
        return $names->first(function ($name) use ($options) {
89
            return in_array($name, $options);
90
        });
91
    }
92
93
    /**
94
     * Get the validation error message.
95
     *
96
     * @return string
97
     */
98
    public function message(): string
99
    {
100
        return __('zipValidator::messages.failed', [
101
            'files' => $this->failedFiles->implode(', '),
102
        ]);
103
    }
104
105
    /**
106
     * Reads ZIP file content and returns collection with result.
107
     *
108
     * @param UploadedFile $value
109
     *
110
     * @return Collection
111
     */
112
    private function readContent(UploadedFile $value): Collection
113
    {
114
        $zipOpen = $this->zip->open($value->path());
115
        throw_unless($zipOpen === true, new ZipException($zipOpen));
116
117
        $content = collect();
118
        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

118
        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...
119
            $content->add($this->zip->statIndex($i));
120
        }
121
122
        $this->zip->close();
123
124
        return $content;
125
    }
126
}
127