@@ -20,12 +20,12 @@ class File implements Rule, DataAwareRule, ValidatorAwareRule
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
*/
@@ -166,7 +166,9 @@ 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
+ *
171
+ * Only affects naked numeric values. Explicit suffixes (MB, MiB) take precedence.
170
172
*/
171
173
public function binary (): static
172
174
{
@@ -175,70 +177,84 @@ public function binary(): static
175
177
}
176
178
177
179
/**
178
- * Set the units for size validation to international.
180
+ * Set the units for size validation to international (1000-based).
181
+ *
182
+ * Only affects naked numeric values. Explicit suffixes (MB, MiB) take precedence.
179
183
*/
180
184
public function international (): static
181
185
{
182
186
$ this ->units = self ::INTERNATIONAL ;
183
187
return $ this ;
184
188
}
185
189
186
-
187
-
188
190
/**
189
- * Indicate that the uploaded file should be exactly a certain size in kilobytes.
191
+ * Indicate that the uploaded file should be exactly a certain size.
192
+ *
193
+ * Supports both numeric values and human-readable sizes with suffixes:
194
+ * - Binary: 1KiB, 1MiB, 1GiB, 1TiB (1024-based)
195
+ * - International: 1KB, 1MB, 1GB, 1TB (1000-based)
196
+ * - Numeric: Uses instance unit setting (binary/international)
190
197
*/
191
- public function size (string |int $ size, ? string $ units = null ): static
198
+ public function size (string |int $ size ): static
192
199
{
193
- $ this ->minimumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
200
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ size );
194
201
$ this ->maximumFileSize = $ this ->minimumFileSize ;
195
202
196
203
return $ this ;
197
204
}
198
205
199
206
/**
200
- * Indicate that the uploaded file should be between a minimum and maximum size in kilobytes.
207
+ * Indicate that the uploaded file should be between a minimum and maximum size.
208
+ *
209
+ * Supports both numeric values and human-readable sizes with suffixes:
210
+ * - Binary: 1KiB, 1MiB, 1GiB, 1TiB (1024-based)
211
+ * - International: 1KB, 1MB, 1GB, 1TB (1000-based)
212
+ * - Numeric: Uses instance unit setting (binary/international)
201
213
*/
202
- public function between (string |int $ minSize , string |int $ maxSize, ? string $ units = null ): static
214
+ public function between (string |int $ minSize , string |int $ maxSize ): static
203
215
{
204
- $ this ->minimumFileSize = $ this ->toKilobytes ($ minSize, $ this -> units ( $ units ) );
205
- $ this ->maximumFileSize = $ this ->toKilobytes ($ maxSize, $ this -> units ( $ units ) );
216
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ minSize );
217
+ $ this ->maximumFileSize = $ this ->toKilobytes ($ maxSize );
206
218
207
219
return $ this ;
208
220
}
209
221
210
222
/**
211
- * Indicate that the uploaded file should be no less than the given number of kilobytes.
223
+ * Indicate that the uploaded file should be no less than the given size.
224
+ *
225
+ * Supports both numeric values and human-readable sizes with suffixes:
226
+ * - Binary: 1KiB, 1MiB, 1GiB, 1TiB (1024-based)
227
+ * - International: 1KB, 1MB, 1GB, 1TB (1000-based)
228
+ * - Numeric: Uses instance unit setting (binary/international)
212
229
*/
213
- public function min (string |int $ size, ? string $ units = null ): static
230
+ public function min (string |int $ size ): static
214
231
{
215
- $ this ->minimumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
232
+ $ this ->minimumFileSize = $ this ->toKilobytes ($ size );
216
233
217
234
return $ this ;
218
235
}
219
236
220
237
/**
221
- * Indicate that the uploaded file should be no more than the given number of kilobytes.
238
+ * Indicate that the uploaded file should be no more than the given size.
239
+ *
240
+ * Supports both numeric values and human-readable sizes with suffixes:
241
+ * - Binary: 1KiB, 1MiB, 1GiB, 1TiB (1024-based)
242
+ * - International: 1KB, 1MB, 1GB, 1TB (1000-based)
243
+ * - Numeric: Uses instance unit setting (binary/international)
222
244
*/
223
- public function max (string |int $ size, ? string $ units = null ): static
245
+ public function max (string |int $ size ): static
224
246
{
225
- $ this ->maximumFileSize = $ this ->toKilobytes ($ size, $ this -> units ( $ units ) );
247
+ $ this ->maximumFileSize = $ this ->toKilobytes ($ size );
226
248
227
249
return $ this ;
228
250
}
229
251
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
252
/**
239
253
* Convert a potentially human-friendly file size to kilobytes.
254
+ *
255
+ * Supports suffix detection with precedence over instance settings.
240
256
*/
241
- protected function toKilobytes (string |int $ size, string $ units ): float |int
257
+ protected function toKilobytes (string |int $ size ): float |int
242
258
{
243
259
if (! is_string ($ size )) {
244
260
return $ size ;
@@ -247,8 +263,8 @@ protected function toKilobytes(string|int $size, string $units): float|int
247
263
if (($ value = $ this ->parseSize ($ size )) === false || $ value < 0 ) {
248
264
throw new InvalidArgumentException ('Invalid numeric value in file size. ' );
249
265
}
250
-
251
- return $ units === self ::BINARY
266
+
267
+ return $ this -> detectUnits ( $ size ) === self ::BINARY
252
268
? $ this ->toBinaryKilobytes ($ size , $ value )
253
269
: $ this ->toInternationalKilobytes ($ size , $ value );
254
270
}
@@ -266,6 +282,22 @@ protected function parseSize($size): false|float
266
282
);
267
283
}
268
284
285
+ /**
286
+ * Detect the suffix and determine appropriate units from a file size string.
287
+ *
288
+ * Returns binary for MiB/GiB/TiB suffixes, international for MB/GB/TB suffixes,
289
+ * or falls back to instance setting for naked values.
290
+ */
291
+ protected function detectUnits (string $ size ): string
292
+ {
293
+ return match (true ) {
294
+ is_numeric ($ size ) => $ this ->units ,
295
+ in_array (strtolower (substr (trim ($ size ), -3 )), ['kib ' , 'mib ' , 'gib ' , 'tib ' ]) => self ::BINARY ,
296
+ in_array (strtolower (substr (trim ($ size ), -2 )), ['kb ' , 'mb ' , 'gb ' , 'tb ' ]) => self ::INTERNATIONAL ,
297
+ default => $ this ->units ,
298
+ };
299
+ }
300
+
269
301
/**
270
302
* Convert a human-friendly file size to kilobytes using the International System.
271
303
*/
@@ -275,19 +307,26 @@ protected function toInternationalKilobytes(string $size, float $value): float|i
275
307
$ this ->protectValueFromOverflow (
276
308
$ this ->prepareValueForPrecision ($ value ),
277
309
! 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
310
+ ? $ this ->getInternationalMultiplier (strtolower (trim ($ size )))
311
+ : 1
287
312
)
288
313
);
289
314
}
290
315
316
+ /**
317
+ * Get the international multiplier for a given size string.
318
+ */
319
+ protected function getInternationalMultiplier (string $ size ): int
320
+ {
321
+ return match (substr ($ size , -2 )) {
322
+ 'kb ' => 1 ,
323
+ 'mb ' => 1_000 ,
324
+ 'gb ' => 1_000_000 ,
325
+ 'tb ' => 1_000_000_000 ,
326
+ default => throw new InvalidArgumentException ('Invalid file size suffix. ' ),
327
+ };
328
+ }
329
+
291
330
/**
292
331
* Convert a human-friendly file size to kilobytes using the Binary System.
293
332
*/
@@ -297,19 +336,26 @@ protected function toBinaryKilobytes(string $size, float $value): float|int
297
336
$ this ->protectValueFromOverflow (
298
337
$ this ->prepareValueForPrecision ($ value ),
299
338
! 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
339
+ ? $ this ->getBinaryMultiplier (strtolower (trim ($ size )))
340
+ : 1
309
341
)
310
342
);
311
343
}
312
344
345
+ /**
346
+ * Get the binary multiplier for a given size string.
347
+ */
348
+ protected function getBinaryMultiplier (string $ size ): int
349
+ {
350
+ return match (substr ($ size , -3 )) {
351
+ 'kib ' => 1 ,
352
+ 'mib ' => 1_024 ,
353
+ 'gib ' => 1_048_576 ,
354
+ 'tib ' => 1_073_741_824 ,
355
+ default => throw new InvalidArgumentException ('Invalid file size suffix. ' ),
356
+ };
357
+ }
358
+
313
359
/**
314
360
* Converts whole numbers to integers for exact arithmetic while keeping
315
361
* fractional numbers as floats; also provides overflow protection by
0 commit comments