13
13
use Illuminate \Support \Traits \Macroable ;
14
14
use InvalidArgumentException ;
15
15
16
- class File implements Rule, DataAwareRule , ValidatorAwareRule
16
+ class File implements DataAwareRule, Rule , ValidatorAwareRule
17
17
{
18
18
use Conditionable, Macroable;
19
19
20
20
/**
21
21
* Binary units flag used for size validation.
22
22
*/
23
- public const BINARY = 'binary ' ;
23
+ protected const BINARY = 'binary ' ;
24
24
25
25
/**
26
26
* International units flag used for size validation.
27
27
*/
28
- public const INTERNATIONAL = 'international ' ;
28
+ protected const INTERNATIONAL = 'international ' ;
29
29
30
30
/**
31
31
* The MIME types that the given file should match. This array may also contain file extensions.
@@ -42,14 +42,14 @@ class File implements Rule, DataAwareRule, ValidatorAwareRule
42
42
protected $ allowedExtensions = [];
43
43
44
44
/**
45
- * The minimum size in kilobytes that the file can be.
45
+ * The minimum file size that the file can be.
46
46
*
47
47
* @var null|int
48
48
*/
49
49
protected $ minimumFileSize = null ;
50
50
51
51
/**
52
- * The maximum size in kilobytes that the file can be.
52
+ * The maximum file size that the file can be.
53
53
*
54
54
* @var null|int
55
55
*/
@@ -127,7 +127,7 @@ public static function default()
127
127
? call_user_func (static ::$ defaultCallback )
128
128
: static ::$ defaultCallback ;
129
129
130
- return $ file instanceof Rule ? $ file : new self () ;
130
+ return $ file instanceof Rule ? $ file : new self ;
131
131
}
132
132
133
133
/**
@@ -149,7 +149,7 @@ public static function image($allowSvg = false)
149
149
*/
150
150
public static function types ($ mimetypes )
151
151
{
152
- return tap (new static () , fn ($ file ) => $ file ->allowedMimetypes = (array ) $ mimetypes );
152
+ return tap (new static , fn ($ file ) => $ file ->allowedMimetypes = (array ) $ mimetypes );
153
153
}
154
154
155
155
/**
@@ -166,89 +166,83 @@ public function extensions($extensions)
166
166
}
167
167
168
168
/**
169
- * Set the units for size validation to binary.
169
+ * Set the units for size validation to binary (1024-based) .
170
170
*/
171
171
public function binary (): static
172
172
{
173
173
$ this ->units = self ::BINARY ;
174
+
174
175
return $ this ;
175
176
}
176
177
177
178
/**
178
- * Set the units for size validation to international.
179
+ * Set the units for size validation to international (1000-based) .
179
180
*/
180
181
public function international (): static
181
182
{
182
183
$ this ->units = self ::INTERNATIONAL ;
184
+
183
185
return $ this ;
184
186
}
185
187
186
-
187
-
188
188
/**
189
- * Indicate that the uploaded file should be exactly a certain size in kilobytes .
189
+ * Indicate that the uploaded file should be exactly a certain size.
190
190
*/
191
- public function size (string |int $ size, ? string $ units = null ): static
191
+ public function size (string |int $ size ): static
192
192
{
193
- $ this ->minimumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
193
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ size );
194
194
$ this ->maximumFileSize = $ this ->minimumFileSize ;
195
195
196
196
return $ this ;
197
197
}
198
198
199
199
/**
200
- * Indicate that the uploaded file should be between a minimum and maximum size in kilobytes .
200
+ * Indicate that the uploaded file should be between a minimum and maximum size.
201
201
*/
202
- public function between (string |int $ minSize , string |int $ maxSize, ? string $ units = null ): static
202
+ public function between (string |int $ minSize , string |int $ maxSize ): static
203
203
{
204
- $ this ->minimumFileSize = $ this ->toKilobytes ($ minSize, $ this -> units ( $ units ) );
205
- $ this ->maximumFileSize = $ this ->toKilobytes ($ maxSize, $ this -> units ( $ units ) );
204
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ minSize );
205
+ $ this ->maximumFileSize = $ this ->toKilobytes ($ maxSize );
206
206
207
207
return $ this ;
208
208
}
209
209
210
210
/**
211
- * Indicate that the uploaded file should be no less than the given number of kilobytes .
211
+ * Indicate that the uploaded file should be no less than the given size .
212
212
*/
213
- public function min (string |int $ size, ? string $ units = null ): static
213
+ public function min (string |int $ size ): static
214
214
{
215
- $ this ->minimumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
215
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ size );
216
216
217
217
return $ this ;
218
218
}
219
219
220
220
/**
221
- * Indicate that the uploaded file should be no more than the given number of kilobytes .
221
+ * Indicate that the uploaded file should be no more than the given size .
222
222
*/
223
- public function max (string |int $ size, ? string $ units = null ): static
223
+ public function max (string |int $ size ): static
224
224
{
225
- $ this ->maximumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
225
+ $ this ->maximumFileSize = $ this ->toKilobytes ($ size );
226
226
227
227
return $ this ;
228
228
}
229
229
230
- /**
231
- * Resolve the units to use for size calculations.
232
- */
233
- protected function units (?string $ units = null ): string
234
- {
235
- return $ units ?? $ this ->units ;
236
- }
237
-
238
230
/**
239
231
* Convert a potentially human-friendly file size to kilobytes.
232
+ *
233
+ * Supports suffix detection with precedence over instance settings.
240
234
*/
241
- protected function toKilobytes (string |int $ size, string $ units ): float |int
235
+ protected function toKilobytes (string |int $ size ): float |int
242
236
{
243
237
if (! is_string ($ size )) {
244
238
return $ size ;
245
239
}
246
240
247
241
if (($ value = $ this ->parseSize ($ size )) === false || $ value < 0 ) {
248
242
throw new InvalidArgumentException ('Invalid numeric value in file size. ' );
249
- }
243
+ }
250
244
251
- return $ units === self ::BINARY
245
+ return $ this -> detectUnits ( $ size ) === self ::BINARY
252
246
? $ this ->toBinaryKilobytes ($ size , $ value )
253
247
: $ this ->toInternationalKilobytes ($ size , $ value );
254
248
}
@@ -266,6 +260,19 @@ protected function parseSize($size): false|float
266
260
);
267
261
}
268
262
263
+ /**
264
+ * Detect the suffix and determine appropriate units from a file size string.
265
+ */
266
+ protected function detectUnits (string $ size ): string
267
+ {
268
+ return match (true ) {
269
+ is_numeric ($ size ) => $ this ->units ,
270
+ in_array (strtolower (substr (trim ($ size ), -3 )), ['kib ' , 'mib ' , 'gib ' , 'tib ' ]) => self ::BINARY ,
271
+ in_array (strtolower (substr (trim ($ size ), -2 )), ['kb ' , 'mb ' , 'gb ' , 'tb ' ]) => self ::INTERNATIONAL ,
272
+ default => $ this ->units ,
273
+ };
274
+ }
275
+
269
276
/**
270
277
* Convert a human-friendly file size to kilobytes using the International System.
271
278
*/
@@ -275,17 +282,24 @@ protected function toInternationalKilobytes(string $size, float $value): float|i
275
282
$ this ->protectValueFromOverflow (
276
283
$ this ->prepareValueForPrecision ($ value ),
277
284
! is_numeric ($ size )
278
- ? match (substr (strtolower (trim ($ size )), -2 )) {
279
- 'kb ' => 1 ,
280
- 'mb ' => 1_000 ,
281
- 'gb ' => 1_000_000 ,
282
- 'tb ' => 1_000_000_000 ,
283
- default => throw new InvalidArgumentException (
284
- 'Invalid file size suffix. Valid suffixes are: KB, MB, GB, TB (case insensitive). '
285
- ),
286
- } : 1
287
- )
288
- );
285
+ ? $ this ->getInternationalMultiplier (strtolower (trim ($ size )))
286
+ : 1
287
+ )
288
+ );
289
+ }
290
+
291
+ /**
292
+ * Get the international multiplier for a given size string.
293
+ */
294
+ protected function getInternationalMultiplier (string $ size ): int
295
+ {
296
+ return match (substr ($ size , -2 )) {
297
+ 'kb ' => 1 ,
298
+ 'mb ' => 1_000 ,
299
+ 'gb ' => 1_000_000 ,
300
+ 'tb ' => 1_000_000_000 ,
301
+ default => throw new InvalidArgumentException ('Invalid file size suffix. ' ),
302
+ };
289
303
}
290
304
291
305
/**
@@ -297,17 +311,24 @@ protected function toBinaryKilobytes(string $size, float $value): float|int
297
311
$ this ->protectValueFromOverflow (
298
312
$ this ->prepareValueForPrecision ($ value ),
299
313
! is_numeric ($ size )
300
- ? match (substr (strtolower (trim ($ size )), -2 )) {
301
- 'kb ' => 1 ,
302
- 'mb ' => 1_024 ,
303
- 'gb ' => 1_048_576 ,
304
- 'tb ' => 1_073_741_824 ,
305
- default => throw new InvalidArgumentException (
306
- 'Invalid file size suffix. Valid suffixes are: KB, MB, GB, TB (case insensitive). '
307
- ),
308
- } : 1
309
- )
310
- );
314
+ ? $ this ->getBinaryMultiplier (strtolower (trim ($ size )))
315
+ : 1
316
+ )
317
+ );
318
+ }
319
+
320
+ /**
321
+ * Get the binary multiplier for a given size string.
322
+ */
323
+ protected function getBinaryMultiplier (string $ size ): int
324
+ {
325
+ return match (substr ($ size , -3 )) {
326
+ 'kib ' => 1 ,
327
+ 'mib ' => 1_024 ,
328
+ 'gib ' => 1_048_576 ,
329
+ 'tib ' => 1_073_741_824 ,
330
+ default => throw new InvalidArgumentException ('Invalid file size suffix. ' ),
331
+ };
311
332
}
312
333
313
334
/**
@@ -329,7 +350,7 @@ protected function prepareValueForPrecision(float $value): float|int
329
350
*/
330
351
protected function protectValueFromOverflow (float |int $ value , int $ multiplier ): float |int
331
352
{
332
- return $ value > PHP_INT_MAX / $ multiplier
353
+ return $ value > PHP_INT_MAX / $ multiplier
333
354
|| $ value < PHP_INT_MIN / $ multiplier
334
355
|| is_float ($ value )
335
356
? (float ) $ value * $ multiplier
0 commit comments