Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
10 / 10
CRAP
100.00% covered (success)
100.00%
1 / 1
FilesValidator
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
10 / 10
28
100.00% covered (success)
100.00%
1 / 1
 getOrganizedFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFile
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 uploaded
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 maxSize
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 mimes
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 ext
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 image
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 maxDim
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 minDim
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 dim
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php declare(strict_types=1);
2/*
3 * This file is part of Aplus Framework Validation Library.
4 *
5 * (c) Natan Felles <natanfelles@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10namespace Framework\Validation;
11
12use Framework\Helpers\ArraySimple;
13
14/**
15 * Class FilesValidator.
16 *
17 * @package validation
18 */
19class FilesValidator
20{
21    /**
22     * @var array<string,mixed>
23     */
24    protected static array $files;
25
26    /**
27     * Get $_FILES in a re-organized way.
28     *
29     * @return array<string,mixed>
30     */
31    protected static function getOrganizedFiles() : array
32    {
33        return static::$files ?? (static::$files = ArraySimple::files());
34    }
35
36    /**
37     * @param string $field
38     *
39     * @return array<string,mixed>|null
40     */
41    protected static function getFile(string $field) : array | null
42    {
43        $files = static::getOrganizedFiles();
44        return ArraySimple::value($field, $files);
45    }
46
47    /**
48     * Validates file is uploaded.
49     *
50     * @param string $field
51     * @param array<string,mixed> $data
52     *
53     * @return bool
54     */
55    public static function uploaded(string $field, array $data = []) : bool
56    {
57        $file = static::getFile($field);
58        if ($file === null) {
59            return false;
60        }
61        return $file['error'] === \UPLOAD_ERR_OK && \is_uploaded_file($file['tmp_name']);
62    }
63
64    /**
65     * Validates file size.
66     *
67     * @param string $field
68     * @param array<string,mixed> $data
69     * @param int $kilobytes
70     *
71     * @return bool
72     */
73    public static function maxSize(string $field, array $data, int $kilobytes) : bool
74    {
75        $uploaded = static::uploaded($field);
76        if ( ! $uploaded) {
77            return false;
78        }
79        $file = static::getFile($field);
80        return $file['size'] <= ($kilobytes * 1024);
81    }
82
83    /**
84     * Validates file accepted MIME types.
85     *
86     * @param string $field
87     * @param array<string,mixed> $data
88     * @param string ...$allowedTypes
89     *
90     * @return bool
91     */
92    public static function mimes(string $field, array $data, string ...$allowedTypes) : bool
93    {
94        $uploaded = static::uploaded($field);
95        if ( ! $uploaded) {
96            return false;
97        }
98        $file = static::getFile($field);
99        $mimeType = \mime_content_type($file['tmp_name']);
100        return \in_array($mimeType, $allowedTypes, true);
101    }
102
103    /**
104     * Validates file accepted extensions.
105     *
106     * NOTE: For greater security use the {@see FilesValidator::mimes()} method
107     * to filter the file type.
108     *
109     * @param string $field
110     * @param array<string,mixed> $data
111     * @param string ...$allowedExtensions
112     *
113     * @return bool
114     */
115    public static function ext(string $field, array $data, string ...$allowedExtensions) : bool
116    {
117        $uploaded = static::uploaded($field);
118        if ( ! $uploaded) {
119            return false;
120        }
121        $file = static::getFile($field);
122        foreach ($allowedExtensions as $extension) {
123            if (\str_ends_with($file['name'], '.' . $extension)) {
124                return true;
125            }
126        }
127        return false;
128    }
129
130    /**
131     * Validates file is an image.
132     *
133     * @param string $field
134     * @param array<string,mixed> $data
135     *
136     * @return bool
137     */
138    public static function image(string $field, array $data = []) : bool
139    {
140        $uploaded = static::uploaded($field);
141        if ( ! $uploaded) {
142            return false;
143        }
144        $file = static::getFile($field);
145        $mime = \mime_content_type($file['tmp_name']) ?: 'application/octet-stream';
146        return \str_starts_with($mime, 'image/');
147    }
148
149    /**
150     * Validates image max dimensions.
151     *
152     * @param string $field
153     * @param array<string,mixed> $data
154     * @param int $width
155     * @param int $height
156     *
157     * @return bool
158     */
159    public static function maxDim(string $field, array $data, int $width, int $height) : bool
160    {
161        $isImage = static::image($field);
162        if ( ! $isImage) {
163            return false;
164        }
165        $file = static::getFile($field);
166        $sizes = \getimagesize($file['tmp_name']);
167        return ! ($sizes === false || $sizes[0] > $width || $sizes[1] > $height);
168    }
169
170    /**
171     * Validates image min dimensions.
172     *
173     * @param string $field
174     * @param array<string,mixed> $data
175     * @param int $width
176     * @param int $height
177     *
178     * @return bool
179     */
180    public static function minDim(string $field, array $data, int $width, int $height) : bool
181    {
182        $isImage = static::image($field);
183        if ( ! $isImage) {
184            return false;
185        }
186        $file = static::getFile($field);
187        $sizes = \getimagesize($file['tmp_name']);
188        return ! ($sizes === false || $sizes[0] < $width || $sizes[1] < $height);
189    }
190
191    /**
192     * Validates image dimensions.
193     *
194     * @param string $field
195     * @param array<string,mixed> $data
196     * @param int $width
197     * @param int $height
198     *
199     * @return bool
200     */
201    public static function dim(string $field, array $data, int $width, int $height) : bool
202    {
203        $isImage = static::image($field);
204        if ( ! $isImage) {
205            return false;
206        }
207        $file = static::getFile($field);
208        $sizes = \getimagesize($file['tmp_name']);
209        return ! ($sizes === false || $sizes[0] !== $width || $sizes[1] !== $height);
210    }
211}