Validator::readContent()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 14
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Orkhanahmadov\ZipValidator;
4
5
use Illuminate\Support\Collection;
6
use Orkhanahmadov\ZipValidator\Exceptions\ZipException;
7
use ZipArchive;
8
9
class Validator
10
{
11
    /**
12
     * @var Collection
13
     */
14
    private $files;
15
    /**
16
     * @var bool
17
     */
18
    private $allowEmpty;
19
20
    /**
21
     * ZipValidator constructor.
22
     *
23
     * @param array|string $files
24
     * @param bool $allowEmpty
25
     */
26
    public function __construct($files, bool $allowEmpty = true)
27
    {
28
        $this->files = Collection::make($files);
0 ignored issues
show
Bug introduced by
$files of type array|string is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

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

28
        $this->files = Collection::make(/** @scrutinizer ignore-type */ $files);
Loading history...
29
        $this->allowEmpty = $allowEmpty;
30
    }
31
32
    /**
33
     * Static function instantiate Validator class with given rules
34
     *
35
     * @param array|string $files
36
     *
37
     * @param bool $allowEmpty
38
     *
39
     * @return Validator
40
     */
41
    public static function rules($files, bool $allowEmpty = true): Validator
42
    {
43
        return new static($files, $allowEmpty);
44
    }
45
46
    /**
47
     * Validates ZIP content with given file path.
48
     *
49
     * @param string $filePath
50
     *
51
     * @return Collection
52
     */
53
    public function validate(string $filePath): Collection
54
    {
55
        $zipContent = $this->readContent($filePath);
56
57
        return $this->files
58
            ->reject(function ($value, $key) use ($zipContent) {
59
                return $this->checkFile($zipContent, $value, $key);
60
            })->map(function ($value, $key) {
61
                return is_int($key) ? $value : $key;
62
            });
63
    }
64
65
    /**
66
     * @param Collection $zipContent
67
     * @param string|int $value
68
     * @param string|int $key
69
     *
70
     * @return bool
71
     */
72
    public function checkFile(Collection $zipContent, $value, $key): bool
73
    {
74
        if (! is_int($value)) {
75
            $entityName = $this->contains($zipContent->pluck('name'), $value);
76
77
            if ($this->allowEmpty) {
78
                return (bool) $entityName;
79
            }
80
81
            return $zipContent->firstWhere('name', $entityName)['size'] > 0;
82
        }
83
84
        $entityName = $this->contains($zipContent->pluck('name'), $key);
85
        if (! $entityName) {
86
            return false;
87
        }
88
89
        $entitySize = $zipContent->firstWhere('name', $entityName)['size'];
90
91
        if ($this->allowEmpty) {
92
            return $entitySize <= $value;
93
        }
94
95
        return $entitySize > 0 && $entitySize <= $value;
96
    }
97
98
    /**
99
     * Checks if file name exists in ZIP file. Returns matching file name, null otherwise.
100
     *
101
     * @param Collection $names
102
     * @param string $search
103
     *
104
     * @return string|null
105
     */
106
    public function contains(Collection $names, string $search): ?string
107
    {
108
        $options = explode('|', $search);
109
110
        return $names->first(function ($name) use ($options) {
111
            foreach ($options as $option) {
112
                if (fnmatch($option, $name)) {
113
                    return true;
114
                }
115
            }
116
            return false;
117
        });
118
    }
119
120
    /**
121
     * Reads ZIP file content and returns collection with result.
122
     *
123
     * @param string $filePath
124
     *
125
     * @return Collection
126
     */
127
    private function readContent(string $filePath): Collection
128
    {
129
        $zip = new ZipArchive();
130
        $zipOpen = $zip->open($filePath);
131
        throw_unless($zipOpen === true, new ZipException($zipOpen));
132
133
        $content = collect();
134
        for ($i = 0; $i < $zip->count(); $i++) {
135
            $content->add($zip->statIndex($i));
0 ignored issues
show
Bug introduced by
$zip->statIndex($i) of type array is incompatible with the type Illuminate\Support\TValue expected by parameter $item of Illuminate\Support\Collection::add(). ( Ignorable by Annotation )

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

135
            $content->add(/** @scrutinizer ignore-type */ $zip->statIndex($i));
Loading history...
136
        }
137
138
        $zip->close();
139
140
        return $content;
141
    }
142
}
143