Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
SizeParser
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
5 / 5
10
100.00% covered (success)
100.00%
1 / 1
 toByte
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
5
 parse
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 validParse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makeParseException
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 makeRegexPattern
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @license MIT
5 * @author hazuki3417<hazuki3417@gmail.com>
6 * @copyright 2023 hazuki3417 all rights reserved.
7 */
8
9namespace Selen\Str;
10
11use InvalidArgumentException;
12
13/**
14 * string型で表現されたデータ量をint型へ変換するクラスです。
15 */
16class SizeParser
17{
18    /** @var string[] SI接頭辞 */
19    public const UNIT_SI_PREFIX = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'RB', 'QB'];
20    /** @var string[] 2進接頭辞 */
21    public const UNIT_BINARY_PREFIX = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', 'RiB', 'QiB'];
22    /** @var string[] その他の接頭辞 */
23    public const UNIT_OTHER_PREFIX = ['byte'];
24
25    /**
26     * string型で表現されたデータ量をbyte単位に変換します
27     *
28     * @param string $value 文字列を渡します
29     *
30     * @return int|float byte数を返します
31     */
32    public static function toByte(string $value)
33    {
34        [
35            'value' => $value,
36            'unit'  => $tmpUnit,
37        ]     = self::parse($value);
38        $unit = \strtolower($tmpUnit);
39
40        if ($unit === 'byte') {
41            // byte指定のみ
42            return $value;
43        }
44
45        $radix       = \strpos($unit, 'i') === false ? 1000 : 1024;
46        $scanChars   = ['k', 'm', 'g', 't', 'p', 'e', 'z', 'y', 'r', 'q'];
47        $selectIndex = 0;
48
49        foreach ($scanChars as $index => $scanChar) {
50            if (\strpos($unit, $scanChar) === false) {
51                continue;
52            }
53            $selectIndex = $index + 1;
54            break;
55        }
56        return $value * pow($radix, ($selectIndex));
57    }
58
59    /**
60     * string型で表現されたデータ量を値と単位に分割します
61     *
62     * @param string $value 文字列を渡します
63     *
64     * @throws InvalidArgumentException パースに失敗したときの例外をスローします
65     *
66     * @return array<string,int|string> 文字列表現されたデータ量を値と単位に分割した配列を返します
67     */
68    public static function parse(string $value)
69    {
70        $pattern = self::makeRegexPattern();
71
72        if (preg_match($pattern, $value, $matches)) {
73            [1 => $value,2 => $unit] = $matches;
74
75            return [
76                'value' => (int) $value,
77                'unit'  => $unit,
78            ];
79        }
80        throw self::makeParseException();
81    }
82
83    /**
84     * string型で表現されたデータ量フォーマットが正しいか検証します
85     *
86     * @param string $value 文字列を渡します
87     *
88     * @return bool 正しい場合はtrueを、それ以外の場合はfalseを返します
89     */
90    public static function validParse(string $value): bool
91    {
92        return \preg_match(self::makeRegexPattern(), $value);
93    }
94
95    /**
96     * string型で表現されたデータ量フォーマットのパースに失敗したときの例外をスローします
97     *
98     * @return InvalidArgumentException パースに失敗したときの例外をスローします
99     */
100    public static function makeParseException()
101    {
102        $format = 'Invalid data format. Expected format %s .';
103        $mes    = \sprintf($format, self::makeRegexPattern());
104        return new InvalidArgumentException($mes);
105    }
106
107    /**
108     * string型で表現されたデータ量フォーマットをパースする正規表現パターンを作成します
109     *
110     * @return string 正規表現パターンを返します
111     */
112    private static function makeRegexPattern(): string
113    {
114        $allowUnits = \array_merge(
115            self::UNIT_SI_PREFIX,
116            self::UNIT_BINARY_PREFIX,
117            self::UNIT_OTHER_PREFIX,
118        );
119        return \sprintf('/^(\d+)(%s)$/', \implode('|', $allowUnits));
120    }
121}