|
1
|
|
|
<?php |
|
2
|
|
|
declare(strict_types=1); |
|
3
|
|
|
/** |
|
4
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
5
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
6
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
7
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
8
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
9
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
10
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
11
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
12
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
13
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
14
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
15
|
|
|
* |
|
16
|
|
|
* This software consists of voluntary contributions made by many individuals |
|
17
|
|
|
* and is licensed under the LGPL. For more information please see |
|
18
|
|
|
* <http://phing.info>. |
|
19
|
|
|
*/ |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* SizeHelper class |
|
23
|
|
|
* |
|
24
|
|
|
* @author Jawira Portugal <[email protected]> |
|
25
|
|
|
*/ |
|
26
|
|
|
class SizeHelper |
|
27
|
|
|
{ |
|
28
|
|
|
const B = 'B'; |
|
29
|
|
|
const KILO = 1000; |
|
30
|
|
|
const KIBI = 1024; |
|
31
|
|
|
const SI = [1 => ['kB', 'kilo', 'kilobyte',], |
|
32
|
|
|
2 => ['MB', 'mega', 'megabyte',], |
|
33
|
|
|
3 => ['GB', 'giga', 'gigabyte',], |
|
34
|
|
|
4 => ['TB', 'tera', 'terabyte',],]; |
|
35
|
|
|
const IEC = [0 => [self::B,], |
|
36
|
|
|
1 => ['k', 'Ki', 'KiB', 'kibi', 'kibibyte',], |
|
37
|
|
|
2 => ['M', 'Mi', 'MiB', 'mebi', 'mebibyte',], |
|
38
|
|
|
3 => ['G', 'Gi', 'GiB', 'gibi', 'gibibyte',], |
|
39
|
|
|
4 => ['T', 'Ti', 'TiB', 'tebi', 'tebibyte',],]; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* Converts strings like '512K', '0.5G', '50M' to bytes. |
|
43
|
|
|
*/ |
|
44
|
73 |
|
public static function fromHumanToBytes(string $human): float |
|
45
|
|
|
{ |
|
46
|
73 |
|
[$size, $unit] = self::parseHuman($human); |
|
47
|
68 |
|
$multiple = self::findUnitMultiple($unit); |
|
48
|
|
|
|
|
49
|
63 |
|
return $size * $multiple; |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* Convert from bytes to any other valid unit. |
|
54
|
|
|
*/ |
|
55
|
62 |
|
public static function fromBytesTo(int $bytes, string $unit): float |
|
56
|
|
|
{ |
|
57
|
62 |
|
$multiple = self::findUnitMultiple($unit); |
|
58
|
|
|
|
|
59
|
51 |
|
return $bytes / $multiple; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Extracts size and unit from strings like '1m', '50M', '100.55K', '2048'. |
|
64
|
|
|
* |
|
65
|
|
|
* - The default unit is 'B'. |
|
66
|
|
|
* - If unit exists then it is returned as-is, even invalid units. |
|
67
|
|
|
* - This function can also handle scientific notation, e.g. '8e10k'. |
|
68
|
|
|
* - It can also handle negative values '-1M'. |
|
69
|
|
|
* - Parsing is not locale aware, this means that '.' (dot) is always used as decimal separator. |
|
70
|
|
|
* |
|
71
|
|
|
* @param string $human Filesize as a human writes it. |
|
72
|
|
|
* |
|
73
|
|
|
* @return array{0: float, 1: string} First element is size, and second is the unit. |
|
74
|
|
|
*/ |
|
75
|
73 |
|
protected static function parseHuman(string $human): array |
|
76
|
|
|
{ |
|
77
|
|
|
// no unit, so we assume bytes |
|
78
|
73 |
|
if (is_numeric($human)) { |
|
79
|
12 |
|
return [floatval($human), self::B]; |
|
80
|
|
|
} |
|
81
|
61 |
|
$parsed = sscanf($human, '%f%s'); |
|
82
|
61 |
|
if (empty($parsed[0])) { |
|
83
|
5 |
|
throw new BuildException("Invalid size '$human'"); |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
56 |
|
return $parsed; |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
/** |
|
90
|
|
|
* Finds the value in bytes of a single "unit". |
|
91
|
|
|
*/ |
|
92
|
113 |
|
protected static function findUnitMultiple(string $unit): int |
|
93
|
|
|
{ |
|
94
|
113 |
|
foreach (self::IEC as $exponent => $choices) { |
|
95
|
113 |
|
if (in_array(strtolower($unit), array_map('strtolower', $choices))) { |
|
96
|
76 |
|
return pow(self::KIBI, $exponent); |
|
97
|
|
|
} |
|
98
|
|
|
} |
|
99
|
39 |
|
foreach (self::SI as $exponent => $choices) { |
|
100
|
39 |
|
if (in_array(strtolower($unit), array_map('strtolower', $choices))) { |
|
101
|
23 |
|
return pow(self::KILO, $exponent); |
|
102
|
|
|
} |
|
103
|
|
|
} |
|
104
|
16 |
|
throw new BuildException("Invalid unit '$unit'"); |
|
105
|
|
|
} |
|
106
|
|
|
} |
|
107
|
|
|
|