├── .gitignore
├── tests
├── bootstrap.php
└── ByteUnits
│ ├── ConversionBetweenSystemsTest.php
│ ├── BoxingTest.php
│ ├── BinarySystemTest.php
│ ├── MetricSystemTest.php
│ ├── ParseTest.php
│ ├── ArithmeticTest.php
│ ├── CompareTest.php
│ ├── FormatInBinarySystemTest.php
│ └── FormatInMetricSystemTest.php
├── src
└── ByteUnits
│ ├── ParseException.php
│ ├── ConversionException.php
│ ├── NegativeBytesException.php
│ ├── functions.php
│ ├── Parser.php
│ ├── PowerScale.php
│ ├── Formatter.php
│ ├── Metric.php
│ ├── Binary.php
│ └── System.php
├── phpunit.xml
├── .travis.yml
├── composer.json
├── LICENSE
├── .vimrc
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | composer.phar
3 | vendor/
4 | composer.lock
5 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tests/
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - 7.0
8 | - 7.1
9 | - 7.2
10 |
11 | before_script:
12 | - composer install --prefer-source
13 |
14 | script: ./vendor/bin/phpunit
15 |
--------------------------------------------------------------------------------
/tests/ByteUnits/ConversionBetweenSystemsTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf('ByteUnits\Metric', bytes(1));
10 | }
11 |
12 | public function testConvertFromMetricToBinarySystem()
13 | {
14 | $this->assertInstanceOf('ByteUnits\Binary', Metric::bytes(1)->asBinary());
15 | }
16 |
17 | public function testConvertFromBinaryToMetricSystem()
18 | {
19 | $this->assertInstanceOf('ByteUnits\Metric', Binary::bytes(1)->asMetric());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gabrielelana/byte-units",
3 | "description": "Library to parse, format and convert byte units",
4 | "type": "library",
5 | "version": "0.5.0",
6 | "keywords": ["byte", "units", "format", "parse", "convert", "size"],
7 | "homepage": "https://github.com/gabrielelana/byte-units",
8 | "license": "MIT",
9 | "authors": [{
10 | "name": "Gabriele Lana",
11 | "email": "gabriele.lana@gmail.com"
12 | }],
13 | "autoload": {
14 | "psr-4": {
15 | "ByteUnits\\": "src/ByteUnits"
16 | },
17 | "files": [
18 | "src/ByteUnits/functions.php"
19 | ]
20 | },
21 | "require": {
22 | "php": ">=5.4.0",
23 | "ext-bcmath": "*"
24 | },
25 | "require-dev": {
26 | "phpunit/phpunit": ">=4.0,<6.0"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/ByteUnits/BoxingTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(bytes(42), box(42));
10 | }
11 |
12 | public function testBoxAString()
13 | {
14 | $this->assertEquals(parse('1.256MB'), box('1.256MB'));
15 | }
16 |
17 | public function testBoxAByteUnit()
18 | {
19 | $byteUnitInMetricSystem = Metric::bytes(42);
20 | $byteUnitInBinarySystem = Binary::bytes(42);
21 | $this->assertEquals($byteUnitInMetricSystem, box($byteUnitInMetricSystem));
22 | $this->assertEquals($byteUnitInBinarySystem, box($byteUnitInBinarySystem));
23 | }
24 |
25 | /**
26 | * @expectedException ByteUnits\ConversionException
27 | */
28 | public function testBoxAnObjectThatIsNotAByteUnit()
29 | {
30 | box(new \StdClass());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/ByteUnits/functions.php:
--------------------------------------------------------------------------------
1 | parse($bytesAsString);
38 | } catch (\Exception $e) {
39 | $lastParseException = $e;
40 | }
41 | }
42 | throw $lastParseException;
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Gabriele Lana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/ByteUnits/Parser.php:
--------------------------------------------------------------------------------
1 | scale = $scale;
15 | $this->system = new ReflectionClass($system);
16 | }
17 |
18 | /**
19 | * @param string $quantityWithUnit
20 | * @return System
21 | * @throws ParseException
22 | */
23 | public function parse($quantityWithUnit)
24 | {
25 | if (preg_match('/(?P[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\W*(?P.*)/', $quantityWithUnit, $matches)) {
26 | $quantity = $matches['quantity'];
27 | if ($this->scale->isKnownUnit($matches['unit'])) {
28 | $unit = $this->scale->normalizeNameOfUnit($matches['unit']);
29 | return $this->system->newInstanceArgs([$this->scale->scaleFromUnit($quantity, $unit)]);
30 | }
31 | if (empty($matches['unit'])) {
32 | return $this->system->newInstanceArgs([$quantity]);
33 | }
34 | }
35 | throw new ParseException("'{$quantityWithUnit}' is not a valid byte format");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/ByteUnits/BinarySystemTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(Binary::bytes(1024), Binary::kilobytes(1));
10 | }
11 |
12 | public function testMegabytesConstructor()
13 | {
14 | $this->assertEquals(Binary::bytes(1048576), Binary::megabytes(1));
15 | }
16 |
17 | public function testGigabytesConstructor()
18 | {
19 | $this->assertEquals(Binary::bytes(1073741824), Binary::gigabytes(1));
20 | }
21 |
22 | public function testTerabytesConstructor()
23 | {
24 | $this->assertEquals(Binary::bytes(1099511627776), Binary::terabytes(1));
25 | }
26 |
27 | public function testPetabytesConstructor()
28 | {
29 | $this->assertEquals(Binary::bytes(1125899906842624), Binary::petabytes(1));
30 | }
31 |
32 | public function testExabytesConstructor()
33 | {
34 | $this->assertEquals(Binary::bytes(1152921504606846976), Binary::exabytes(1));
35 | }
36 |
37 | /**
38 | * @expectedException ByteUnits\NegativeBytesException
39 | */
40 | public function testCannotBeNegative()
41 | {
42 | Binary::bytes(-1);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/ByteUnits/MetricSystemTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(Metric::bytes(1000), Metric::kilobytes(1));
10 | }
11 |
12 | public function testMegabytesConstructor()
13 | {
14 | $this->assertEquals(Metric::bytes(1000000), Metric::megabytes(1));
15 | }
16 |
17 | public function testGigabytesConstructor()
18 | {
19 | $this->assertEquals(Metric::bytes(1000000000), Metric::gigabytes(1));
20 | }
21 |
22 | public function testTerabytesConstructor()
23 | {
24 | $this->assertEquals(Metric::bytes(1000000000000), Metric::terabytes(1));
25 | }
26 |
27 | public function testPetabytesConstructor()
28 | {
29 | $this->assertEquals(Metric::bytes(1000000000000000), Metric::petabytes(1));
30 | }
31 |
32 | public function testExabytesConstructor()
33 | {
34 | $this->assertEquals(Metric::bytes(1000000000000000000), Metric::exabytes(1));
35 | }
36 |
37 | /**
38 | * @expectedException ByteUnits\NegativeBytesException
39 | */
40 | public function testCannotBeNegative()
41 | {
42 | Metric::bytes(-1);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/ByteUnits/ParseTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(Metric::bytes(1000), parse('1.00kB'));
10 | $this->assertEquals(Metric::bytes(1250000), parse('1.25MB'));
11 | }
12 |
13 | public function testParseInBinarySystem()
14 | {
15 | $this->assertEquals(Binary::bytes(1024), parse('1.00KiB'));
16 | $this->assertEquals(Binary::bytes(1310720), parse('1.25MiB'));
17 | }
18 |
19 | public function testParseWithoutUnit()
20 | {
21 | $this->assertEquals(Metric::bytes(1000), parse('1000'));
22 | }
23 |
24 | public function testParseWithSeparator()
25 | {
26 | $this->assertEquals(Metric::bytes(1000), parse('1.00 kB'));
27 | $this->assertEquals(Metric::bytes(1000), parse('1.00/kB'));
28 | $this->assertEquals(Metric::bytes(1000), parse('1.00~~~kB'));
29 | }
30 |
31 | /**
32 | * @expectedException ByteUnits\ParseException
33 | */
34 | public function testInvalidByteFormat()
35 | {
36 | parse('Not a valid byte format');
37 | }
38 |
39 | /**
40 | * @expectedException ByteUnits\ParseException
41 | */
42 | public function testInvalidByteFormatForBinarySystem()
43 | {
44 | Binary::parse('1.00kB');
45 | }
46 |
47 | /**
48 | * @expectedException ByteUnits\ParseException
49 | */
50 | public function testInvalidByteFormatForMetricSystem()
51 | {
52 | Metric::parse('1.00KiB');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/ByteUnits/ArithmeticTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(Metric::bytes(10), Metric::bytes(5)->add(Metric::bytes(5)));
10 | $this->assertEquals(Binary::bytes(10), Binary::bytes(5)->add(Binary::bytes(5)));
11 | }
12 |
13 | public function testRemoveInSameUnitSystem()
14 | {
15 | $this->assertEquals(Metric::bytes(3), Metric::bytes(5)->remove(Metric::bytes(2)));
16 | $this->assertEquals(Binary::bytes(3), Binary::bytes(5)->remove(Binary::bytes(2)));
17 | }
18 |
19 | public function testAutoboxing()
20 | {
21 | $this->assertEquals(Metric::bytes(10), Metric::bytes(5)->add(5));
22 | $this->assertEquals(Metric::bytes(10), Metric::bytes(5)->add('5B'));
23 | $this->assertEquals(Metric::bytes(3), Metric::bytes(5)->remove(2));
24 | $this->assertEquals(Metric::bytes(3), Metric::bytes(5)->remove('2B'));
25 | }
26 |
27 | /**
28 | * @expectedException ByteUnits\NegativeBytesException
29 | */
30 | public function testCannotRemoveMoreBytesThanYouHave()
31 | {
32 | Metric::bytes(5)->remove(Metric::bytes(10));
33 | }
34 |
35 | public function testPreserveSystemUnitOfReceiver()
36 | {
37 | $this->assertEquals(Metric::bytes(3), Metric::bytes(5)->remove(Binary::bytes(2)));
38 | $this->assertNotEquals(Binary::bytes(3), Metric::bytes(5)->remove(Binary::bytes(2)));
39 | }
40 |
41 | public function testPreserveFormatPrecisionOfReceiver()
42 | {
43 | $result = Metric::bytes(3000, 6)->add(Binary::bytes(256, 2));
44 | $this->assertEquals(Metric::bytes(3256, 6)->format(), $result->format());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/ByteUnits/PowerScale.php:
--------------------------------------------------------------------------------
1 | base = $base;
14 | $this->scale = $scale;
15 | $this->precision = $precision;
16 | }
17 |
18 | public function scaleToUnit($quantity, $unit)
19 | {
20 | if ($quantity === "0") return "0";
21 | return bcdiv(
22 | $quantity,
23 | bcpow($this->base, $this->scale[$unit], $this->precision),
24 | $this->precision
25 | );
26 | }
27 |
28 | public function scaleFromUnit($quantity, $unit)
29 | {
30 | return $quantity * bcpow(
31 | $this->base,
32 | $this->scale[$unit],
33 | $this->precision
34 | );
35 | }
36 |
37 | public function isKnownUnit($unitAsString)
38 | {
39 | return preg_match(
40 | '/^(?:' . implode('|', array_keys($this->scale)) . ')$/i',
41 | trim($unitAsString)
42 | );
43 | }
44 |
45 | public function normalizeNameOfUnit($unitAsString)
46 | {
47 | foreach ($this->scale as $unit => $_) {
48 | if (strtolower($unit) === strtolower($unitAsString)) {
49 | return $unit;
50 | }
51 | }
52 | }
53 |
54 | public function normalUnitFor($quantity)
55 | {
56 | if ($quantity === 0) return "B";
57 | foreach ($this->scale as $unit => $_) {
58 | $scaled = $this->scaleToUnit($quantity, $unit);
59 | if (bccomp($scaled, 1) >= 0) {
60 | return $unit;
61 | }
62 | }
63 | }
64 |
65 | public function isBaseUnit($unit)
66 | {
67 | return (!isset($this->scale[$unit]) || $this->scale[$unit] === 0);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/ByteUnits/Formatter.php:
--------------------------------------------------------------------------------
1 | converter = $converter;
13 | $this->precision = $precision;
14 | }
15 |
16 | public function precision()
17 | {
18 | return $this->precision;
19 | }
20 |
21 | public function format($numberOfBytes, $howToFormat, $separator)
22 | {
23 | $precision = $this->precisionFrom($howToFormat);
24 | $byteUnit = $this->byteUnitToFormatTo($numberOfBytes, $howToFormat);
25 | return $this->formatInByteUnit($numberOfBytes, $byteUnit, $precision, $separator);
26 | }
27 |
28 | private function precisionFrom($howToFormat)
29 | {
30 | if (is_integer($howToFormat)) {
31 | return $howToFormat;
32 | }
33 | if (is_string($howToFormat)) {
34 | if (preg_match('/^.*\/(?0*)$/', $howToFormat, $matches)) {
35 | return strlen($matches['precision']);
36 | }
37 | if (preg_match('/^.*\/(?\d+)$/', $howToFormat, $matches)) {
38 | return intval($matches['precision']);
39 | }
40 | }
41 | return $this->precision;
42 | }
43 |
44 | private function byteUnitToFormatTo($numberOfBytes, $howToFormat)
45 | {
46 | if (is_string($howToFormat)) {
47 | if (preg_match("/^(?P[^\/]+)(?:\/.*$)?/i", $howToFormat, $matches)) {
48 | if ($this->converter->isKnownUnit($matches['unit'])) {
49 | return $this->converter->normalizeNameOfUnit($matches['unit']);
50 | }
51 | }
52 | }
53 | return $this->converter->normalUnitFor($numberOfBytes);
54 | }
55 |
56 | private function formatInByteUnit($numberOfBytes, $byteUnit, $precision, $separator)
57 | {
58 | $scaled = $this->converter->scaleToUnit($numberOfBytes, $byteUnit);
59 | if($byteUnit == null) $byteUnit = "B";
60 | if ($this->converter->isBaseUnit($byteUnit)) {
61 | return sprintf("%d%s%s", $scaled, $separator, $byteUnit);
62 | }
63 | return sprintf("%.{$precision}f%s%s", $scaled, $separator, $byteUnit);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/ByteUnits/Metric.php:
--------------------------------------------------------------------------------
1 | 8, 'ZB'=>7, 'EB'=>6, 'PB'=>5, 'TB'=>4, 'GB'=>3, 'MB'=>2, 'kB'=>1, 'B'=>0];
9 | private static $scale;
10 | private static $parser;
11 |
12 | public function __construct($numberOfBytes, $formatWithPrecision = self::DEFAULT_FORMAT_PRECISION)
13 | {
14 | parent::__construct($numberOfBytes, new Formatter(self::scale(), $formatWithPrecision));
15 | }
16 |
17 | /**
18 | * @param int $numberOf
19 | * @return Metric
20 | */
21 | public static function kilobytes($numberOf)
22 | {
23 | return new self(self::scale()->scaleFromUnit($numberOf, 'kB'));
24 | }
25 |
26 | /**
27 | * @param int $numberOf
28 | * @return Metric
29 | */
30 | public static function megabytes($numberOf)
31 | {
32 | return new self(self::scale()->scaleFromUnit($numberOf, 'MB'));
33 | }
34 |
35 | /**
36 | * @param int $numberOf
37 | * @return Metric
38 | */
39 | public static function gigabytes($numberOf)
40 | {
41 | return new self(self::scale()->scaleFromUnit($numberOf, 'GB'));
42 | }
43 |
44 | /**
45 | * @param int $numberOf
46 | * @return Metric
47 | */
48 | public static function terabytes($numberOf)
49 | {
50 | return new self(self::scale()->scaleFromUnit($numberOf, 'TB'));
51 | }
52 |
53 | /**
54 | * @param int $numberOf
55 | * @return Metric
56 | */
57 | public static function petabytes($numberOf)
58 | {
59 | return new self(self::scale()->scaleFromUnit($numberOf, 'PB'));
60 | }
61 |
62 | /**
63 | * @param int $numberOf
64 | * @return Metric
65 | */
66 | public static function exabytes($numberOf)
67 | {
68 | return new self(self::scale()->scaleFromUnit($numberOf, 'EB'));
69 | }
70 |
71 | /**
72 | * @return PowerScale
73 | */
74 | public static function scale()
75 | {
76 | return self::$scale = self::$scale ?: new PowerScale(self::$base, self::$suffixes, self::COMPUTE_WITH_PRECISION);
77 | }
78 |
79 | /**
80 | * @return Parser
81 | */
82 | public static function parser()
83 | {
84 | return self::$parser = self::$parser ?: new Parser(self::scale(), __CLASS__);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/ByteUnits/Binary.php:
--------------------------------------------------------------------------------
1 | 8, 'ZiB'=>7, 'EiB'=>6, 'PiB'=>5, 'TiB'=>4, 'GiB'=>3, 'MiB'=>2, 'KiB'=>1, 'B'=>0];
9 | private static $scale;
10 | private static $parser;
11 |
12 | /**
13 | * @param int $numberOf
14 | * @return Binary
15 | */
16 | public static function kilobytes($numberOf)
17 | {
18 | return new self(self::scale()->scaleFromUnit($numberOf, 'KiB'));
19 | }
20 |
21 | /**
22 | * @param int $numberOf
23 | * @return Binary
24 | */
25 | public static function megabytes($numberOf)
26 | {
27 | return new self(self::scale()->scaleFromUnit($numberOf, 'MiB'));
28 | }
29 |
30 | /**
31 | * @param int $numberOf
32 | * @return Binary
33 | */
34 | public static function gigabytes($numberOf)
35 | {
36 | return new self(self::scale()->scaleFromUnit($numberOf, 'GiB'));
37 | }
38 |
39 | /**
40 | * @param int $numberOf
41 | * @return Binary
42 | */
43 | public static function terabytes($numberOf)
44 | {
45 | return new self(self::scale()->scaleFromUnit($numberOf, 'TiB'));
46 | }
47 |
48 | /**
49 | * @param int $numberOf
50 | * @return Binary
51 | */
52 | public static function petabytes($numberOf)
53 | {
54 | return new self(self::scale()->scaleFromUnit($numberOf, 'PiB'));
55 | }
56 |
57 | /**
58 | * @param int $numberOf
59 | * @return Binary
60 | */
61 | public static function exabytes($numberOf)
62 | {
63 | return new self(self::scale()->scaleFromUnit($numberOf, 'EiB'));
64 | }
65 |
66 | /**
67 | * @param int $numberOf
68 | * @return Binary
69 | */
70 | public function __construct($numberOfBytes, $formatWithPrecision = self::DEFAULT_FORMAT_PRECISION)
71 | {
72 | parent::__construct($numberOfBytes, new Formatter(self::scale(), $formatWithPrecision));
73 | }
74 |
75 |
76 | /**
77 | * @return PowerScale
78 | */
79 | public static function scale()
80 | {
81 | return self::$scale = self::$scale ?: new PowerScale(self::$base, self::$suffixes, self::COMPUTE_WITH_PRECISION);
82 | }
83 |
84 |
85 | /**
86 | * @return Parser
87 | */
88 | public static function parser()
89 | {
90 | return self::$parser = self::$parser ?: new Parser(self::scale(), __CLASS__);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/tests/ByteUnits/CompareTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(Metric::bytes(1)->isEqualTo(Metric::bytes(1)));
10 | $this->assertTrue(Metric::bytes(1)->isGreaterThanOrEqualTo(Metric::bytes(1)));
11 | $this->assertTrue(Metric::bytes(5)->isGreaterThan(Metric::bytes(1)));
12 | $this->assertTrue(Metric::bytes(1)->isLessThanOrEqualTo(Metric::bytes(1)));
13 | $this->assertTrue(Metric::bytes(1)->isLessThan(Metric::bytes(5)));
14 |
15 | $this->assertTrue(Binary::bytes(1)->isEqualTo(Binary::bytes(1)));
16 | $this->assertTrue(Binary::bytes(1)->isGreaterThanOrEqualTo(Binary::bytes(1)));
17 | $this->assertTrue(Binary::bytes(5)->isGreaterThan(Binary::bytes(1)));
18 | $this->assertTrue(Binary::bytes(1)->isLessThanOrEqualTo(Binary::bytes(1)));
19 | $this->assertTrue(Binary::bytes(1)->isLessThan(Binary::bytes(5)));
20 | }
21 |
22 | public function testCompareWithOtherUnitSystem()
23 | {
24 | $this->assertTrue(Metric::bytes(1)->isEqualTo(Binary::bytes(1)));
25 | $this->assertTrue(Metric::bytes(1)->isGreaterThanOrEqualTo(Binary::bytes(1)));
26 | $this->assertTrue(Metric::bytes(5)->isGreaterThan(Binary::bytes(1)));
27 | $this->assertTrue(Metric::bytes(1)->isLessThanOrEqualTo(Binary::bytes(1)));
28 | $this->assertTrue(Metric::bytes(1)->isLessThan(Binary::bytes(5)));
29 |
30 | $this->assertTrue(Binary::bytes(1)->isEqualTo(Metric::bytes(1)));
31 | $this->assertTrue(Binary::bytes(1)->isGreaterThanOrEqualTo(Metric::bytes(1)));
32 | $this->assertTrue(Binary::bytes(5)->isGreaterThan(Metric::bytes(1)));
33 | $this->assertTrue(Binary::bytes(1)->isLessThanOrEqualTo(Metric::bytes(1)));
34 | $this->assertTrue(Binary::bytes(1)->isLessThan(Metric::bytes(5)));
35 | }
36 |
37 | public function testAutoboxing()
38 | {
39 | $this->assertTrue(Metric::bytes(1)->isEqualTo(1));
40 | $this->assertTrue(Metric::bytes(1)->isEqualTo('1B'));
41 | $this->assertTrue(Metric::bytes(1)->isGreaterThanOrEqualTo(1));
42 | $this->assertTrue(Metric::bytes(1)->isGreaterThanOrEqualTo('1B'));
43 | $this->assertTrue(Metric::bytes(5)->isGreaterThan(1));
44 | $this->assertTrue(Metric::bytes(5)->isGreaterThan('1B'));
45 | $this->assertTrue(Metric::bytes(1)->isLessThanOrEqualTo(1));
46 | $this->assertTrue(Metric::bytes(1)->isLessThanOrEqualTo('1B'));
47 | $this->assertTrue(Metric::bytes(1)->isLessThan(5));
48 | $this->assertTrue(Metric::bytes(1)->isLessThan('5B'));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/ByteUnits/FormatInBinarySystemTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(new Binary(1), Binary::bytes(1));
10 | }
11 |
12 | public function testFormatInMostReadableByteUnit()
13 | {
14 | $this->assertEquals('0B', Binary::bytes(0)->format());
15 | $this->assertEquals('1B', Binary::bytes(1)->format());
16 | $this->assertEquals('1.00KiB', Binary::bytes(1024)->format());
17 | $this->assertEquals('1.25KiB', Binary::bytes(1280)->format());
18 | $this->assertEquals('1.50MiB', Binary::bytes(1572864)->format());
19 | $this->assertEquals('1.75GiB', Binary::bytes(1879048192)->format());
20 | $this->assertEquals('2.00TiB', Binary::bytes(2199023255552)->format());
21 | }
22 |
23 | public function testFormatInMostReadableByteUnitWithPrecision()
24 | {
25 | $this->assertEquals('1.201216MiB', Binary::bytes(1259566)->format(6));
26 | $this->assertEquals('1.201216MiB', Binary::bytes(1259566)->format('/000000'));
27 | $this->assertEquals('1.201216MiB', Binary::bytes(1259566)->format('/6'));
28 | }
29 |
30 | public function testFormatInMostReadableByteUnitWithSepartor()
31 | {
32 | $this->assertEquals('1.20 MiB', Binary::bytes(1259566)->format(2, ' '));
33 | $this->assertEquals('1.20/MiB', Binary::bytes(1259566)->format(2, '/'));
34 | }
35 |
36 | public function testFormatInByteUnit()
37 | {
38 | $bytes = Binary::bytes(1250000000);
39 | $this->assertEquals('1250000000B', $bytes->format('B'));
40 | $this->assertEquals('1220703.12KiB', $bytes->format('KiB'));
41 | $this->assertEquals('1192.09MiB', $bytes->format('MiB'));
42 | $this->assertEquals('1.16GiB', $bytes->format('GiB'));
43 | }
44 |
45 | public function testFormatInByteUnitIsCaseInsensitive()
46 | {
47 | $bytes = Binary::bytes(1250000000);
48 | $this->assertEquals('1250000000B', $bytes->format('B'));
49 | $this->assertEquals('1250000000B', $bytes->format('b'));
50 | $this->assertEquals('1220703.12KiB', $bytes->format('KiB'));
51 | $this->assertEquals('1220703.12KiB', $bytes->format('Kib'));
52 | $this->assertEquals('1220703.12KiB', $bytes->format('KIB'));
53 | $this->assertEquals('1220703.12KiB', $bytes->format('kiB'));
54 | $this->assertEquals('1220703.12KiB', $bytes->format('kib'));
55 | }
56 |
57 | public function testFormatInByteUnitWithPrecision()
58 | {
59 | $bytes = Binary::bytes(1250000000);
60 | $this->assertEquals('1.164153GiB', $bytes->format('GiB/000000'));
61 | $this->assertEquals('1.164GiB', $bytes->format('GiB/000'));
62 | $this->assertEquals('0.001TiB', $bytes->format('TiB/000'));
63 | $this->assertEquals('0.001137TiB', $bytes->format('TiB/6'));
64 | }
65 |
66 | public function testNumberOfBytes()
67 | {
68 | $this->assertEquals('0', Binary::bytes(0)->numberOfBytes());
69 | $this->assertEquals('1', Binary::bytes(1)->numberOfBytes());
70 | $this->assertEquals('1024', Binary::bytes(1024)->numberOfBytes());
71 | $this->assertEquals('1280', Binary::bytes(1280)->numberOfBytes());
72 | $this->assertEquals('1572864', Binary::bytes(1572864)->numberOfBytes());
73 | $this->assertEquals('1879048192', Binary::bytes(1879048192)->numberOfBytes());
74 | $this->assertEquals('2199023255552', Binary::bytes(2199023255552)->numberOfBytes());
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/ByteUnits/FormatInMetricSystemTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(new Metric(1), Metric::bytes(1));
10 | }
11 |
12 | public function testFormatInMostReadableByteUnit()
13 | {
14 | $this->assertEquals('0B', Metric::bytes(0)->format());
15 | $this->assertEquals('1B', Metric::bytes(1)->format());
16 | $this->assertEquals('1.00kB', Metric::bytes(1000)->format());
17 | $this->assertEquals('1.25kB', Metric::bytes(1250)->format());
18 | $this->assertEquals('1.50MB', Metric::bytes(1500000)->format());
19 | $this->assertEquals('1.75GB', Metric::bytes(1750000000)->format());
20 | $this->assertEquals('2.00TB', Metric::bytes(2000000000000)->format());
21 | $this->assertEquals('2.25PB', Metric::bytes(2250000000000000)->format());
22 | $this->assertEquals('2.50EB', Metric::bytes(2500000000000000000)->format());
23 | $this->assertEquals('2.75ZB', Metric::bytes(2750000000000000000000)->format());
24 | $this->assertEquals('3.00YB', Metric::bytes(3000000000000000000000000)->format());
25 | }
26 |
27 | public function testFormatInMostReadableByteUnitWithPrecision()
28 | {
29 | $this->assertEquals('1.259566MB', Metric::bytes(1259566)->format(6));
30 | $this->assertEquals('1.259566MB', Metric::bytes(1259566)->format('/000000'));
31 | $this->assertEquals('1.259566MB', Metric::bytes(1259566)->format('/6'));
32 | }
33 |
34 | public function testFormatInMostReadableByteUnitWithSepartor()
35 | {
36 | $this->assertEquals('1.26 MB', Metric::bytes(1259566)->format(2, ' '));
37 | $this->assertEquals('1.26/MB', Metric::bytes(1259566)->format(2, '/'));
38 | }
39 |
40 | public function testFormatInByteUnit()
41 | {
42 | $bytes = Metric::bytes(1250000000);
43 | $this->assertEquals('1250000000B', $bytes->format('B'));
44 | $this->assertEquals('1250000.00kB', $bytes->format('kB'));
45 | $this->assertEquals('1250.00MB', $bytes->format('MB'));
46 | $this->assertEquals('1.25GB', $bytes->format('GB'));
47 | }
48 |
49 | public function testFormatInByteUnitIsCaseInsensitive()
50 | {
51 | $bytes = Metric::bytes(1250000000);
52 | $this->assertEquals('1250000000B', $bytes->format('b'));
53 | $this->assertEquals('1250000.00kB', $bytes->format('KB'));
54 | $this->assertEquals('1250000.00kB', $bytes->format('kb'));
55 | $this->assertEquals('1250.00MB', $bytes->format('MB'));
56 | $this->assertEquals('1250.00MB', $bytes->format('mB'));
57 | $this->assertEquals('1250.00MB', $bytes->format('Mb'));
58 | $this->assertEquals('1250.00MB', $bytes->format('mb'));
59 | $this->assertEquals('1.25GB', $bytes->format('GB'));
60 | $this->assertEquals('1.25GB', $bytes->format('gB'));
61 | $this->assertEquals('1.25GB', $bytes->format('Gb'));
62 | $this->assertEquals('1.25GB', $bytes->format('gb'));
63 | }
64 |
65 | public function testFormatInByteUnitWithPrecision()
66 | {
67 | $this->assertEquals('1.250000GB', Metric::bytes(1250000000)->format('GB/000000'));
68 | $this->assertEquals('0.001250GB', Metric::bytes(1250000)->format('GB/000000'));
69 | $this->assertEquals('0.000001GB', Metric::bytes(1250)->format('GB/000000'));
70 | }
71 |
72 | public function testFormatWithRoundPrecision()
73 | {
74 | $this->assertEquals('1MB', Metric::bytes(1259566)->format(0));
75 | $this->assertEquals('1MB', Metric::bytes(1259566)->format('MB/'));
76 | $this->assertEquals('1MB', Metric::bytes(1259566, 0)->format());
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/.vimrc:
--------------------------------------------------------------------------------
1 | " autoload the local .vimrc file you need to have
2 | " https://github.com/MarcWeber/vim-addon-local-vimrc
3 | " plugin installed
4 |
5 | let g:syntastic_php_checkers = ['php']
6 | let g:syntastic_mode_map = {'mode': 'active'}
7 |
8 |
9 | let g:ctrlp_custom_ignore = '\.git$\|\.tmp$\|\.work$\|vendor$'
10 |
11 | autocmd Filetype php nnoremap a :!vendor/bin/phpunit
12 | autocmd Filetype php nnoremap o :call OpenCurrentTest()
13 | autocmd Filetype php nnoremap t
14 | \ :setlocal nocursorline call RunCurrentTest() setlocal cursorline
15 | autocmd Filetype php nnoremap f
16 | \ :setlocal nocursorline call RunCurrentFunction() setlocal cursorline
17 | autocmd Filetype php nnoremap e
18 | \ :setlocal nocursorline call RunCurrentLine() setlocal cursorline
19 |
20 | " note that the following only works with tpope/vim-commentary plugin
21 | " cannot say something like if exists("g:loaded_commentary") because
22 | " this file is sourced before commentary plugin, need to find a solution
23 | " for this...
24 | autocmd Filetype php nnoremap c :g/\/ :normal gcc
25 |
26 |
27 | function! RunCurrentLine()
28 | exec '!php -r "var_dump(' . substitute(getline('.'), '^\s\+\|;$', '', 'g') . ');"'
29 | endfunction
30 |
31 | function! RunCurrentFunction()
32 | let l:current_file=expand('%:p')
33 | if match(l:current_file, 'Test\.php$') != -1
34 | let l:function_pattern='\C^\s*\%(public\s\+\|static\s\+\|abstract\s\+\|protected\s\+\|private\s\+\)*function\s\+\([^(]\+\)\s*(.*$'
35 | let l:function_line=search(l:function_pattern, 'bcnW')
36 | if l:function_line > 0
37 | let l:matches=matchlist(getline(l:function_line), l:function_pattern)
38 | exec '!vendor/bin/phpunit --filter="' . l:matches[1] . '$"' l:current_file
39 | endif
40 | endif
41 | endfunction
42 |
43 |
44 | function! RunCurrentTest()
45 | let l:current_file=expand('%:p')
46 | let l:test_file='nothing'
47 | if match(l:current_file, 'Test\.php$') != -1
48 | let l:test_file=l:current_file
49 | else
50 | let l:test_file=SearchForRelatedTestFile(l:current_file)
51 | endif
52 | if l:test_file != 'nothing'
53 | exec '!vendor/bin/phpunit' l:test_file
54 | else
55 | echo 'sorry, nothing to run :-('
56 | endif
57 | endfunction
58 |
59 | function! OpenCurrentTest()
60 | let l:current_file=expand("%:p")
61 | let l:test_file="nothing"
62 | let l:test_file=SearchForRelatedTestFile(l:current_file)
63 | if l:test_file != "nothing"
64 | exec ":belowright :split " l:test_file
65 | else
66 | echo "sorry, nothing to open :-("
67 | endif
68 | endfunction
69 |
70 |
71 | function! SearchForRelatedTestFile(file_path)
72 | let l:file_name=fnamemodify(a:file_path, ":t")
73 | let l:test_file_name=fnamemodify(l:file_name, ":r") . "Test.php"
74 | let l:project_root_path=ProjectRootGuess(a:file_path)
75 | let l:found=system("find '".l:project_root_path."/tests' -name '".l:test_file_name."'")
76 | let l:number_of_file_founds=strlen(substitute(l:found, "[^\n]", "", "g"))
77 | if l:number_of_file_founds == 1
78 | return l:found
79 | endif
80 | endfunction
81 |
82 |
83 | function! ProjectRootGuess(file_path)
84 | for l:marker in [".git", ".vimrc"]
85 | let l:result=""
86 | let l:pivot=a:file_path
87 | while l:pivot!=fnamemodify(l:pivot, ":h")
88 | let l:pivot=fnamemodify(l:pivot, ":h")
89 | if len(glob(l:pivot."/".l:marker))
90 | let l:result=l:pivot
91 | endif
92 | endwhile
93 | if len(l:result)
94 | return l:result
95 | endif
96 | endfor
97 | return filereadable(a:file_path) ? fnamemodify(a:file_path, ":h") : a:file_path
98 | endfunction
99 |
--------------------------------------------------------------------------------
/src/ByteUnits/System.php:
--------------------------------------------------------------------------------
1 | parse($bytesAsString);
30 | }
31 |
32 | public function __construct($numberOfBytes, $formatter)
33 | {
34 | $this->formatter = $formatter;
35 | $this->numberOfBytes = $this->ensureIsNotNegative($this->normalize($numberOfBytes));
36 | }
37 |
38 | /**
39 | * @param System $another
40 | * @return System
41 | */
42 | public function add($another)
43 | {
44 | return new static(
45 | bcadd($this->numberOfBytes, box($another)->numberOfBytes, self::COMPUTE_WITH_PRECISION),
46 | $this->formatter->precision()
47 | );
48 | }
49 |
50 | /**
51 | * @param System $another
52 | * @return System
53 | */
54 | public function remove($another)
55 | {
56 | return new static(
57 | bcsub($this->numberOfBytes, box($another)->numberOfBytes, self::COMPUTE_WITH_PRECISION),
58 | $this->formatter->precision()
59 | );
60 | }
61 |
62 | /**
63 | * @param System $another
64 | * @return bool
65 | */
66 | public function isEqualTo($another)
67 | {
68 | return self::compare($this, box($another)) === 0;
69 | }
70 |
71 | /**
72 | * @param System $another
73 | * @return bool
74 | */
75 | public function isGreaterThanOrEqualTo($another)
76 | {
77 | return self::compare($this, box($another)) >= 0;
78 | }
79 |
80 | /**
81 | * @param System $another
82 | * @return bool
83 | */
84 | public function isGreaterThan($another)
85 | {
86 | return self::compare($this, box($another)) > 0;
87 | }
88 |
89 | /**
90 | * @param System $another
91 | * @return bool
92 | */
93 | public function isLessThanOrEqualTo($another)
94 | {
95 | return self::compare($this, box($another)) <= 0;
96 | }
97 |
98 | /**
99 | * @param System $another
100 | * @return bool
101 | */
102 | public function isLessThan($another)
103 | {
104 | return self::compare($this, box($another)) < 0;
105 | }
106 |
107 | /**
108 | * @param System $left
109 | * @param System $right
110 | * @return int
111 | */
112 | public static function compare($left, $right)
113 | {
114 | return bccomp(
115 | $left->numberOfBytes,
116 | $right->numberOfBytes,
117 | self::COMPUTE_WITH_PRECISION
118 | );
119 | }
120 |
121 | /**
122 | * @param string $howToFormat
123 | * @param string $separator
124 | * @return string
125 | */
126 | public function format($howToFormat = null, $separator = '')
127 | {
128 | return $this->formatter->format($this->numberOfBytes, $howToFormat, $separator);
129 | }
130 |
131 | /**
132 | * @return System
133 | */
134 | public function asBinary()
135 | {
136 | return Binary::bytes($this->numberOfBytes);
137 | }
138 |
139 | /**
140 | * @return System
141 | */
142 | public function asMetric()
143 | {
144 | return Metric::bytes($this->numberOfBytes);
145 | }
146 |
147 | /**
148 | * @param string $numberOfBytes
149 | * @return int
150 | */
151 | private function normalize($numberOfBytes)
152 | {
153 | $numberOfBytes = (string) $numberOfBytes;
154 | if (preg_match('/^(?P\d+(?:\.\d+))E\+(?P\d+)$/', $numberOfBytes, $matches)) {
155 | $numberOfBytes = bcmul(
156 | $matches['coefficient'],
157 | bcpow($base = 10, $matches['exponent'], self::COMPUTE_WITH_PRECISION)
158 | );
159 | }
160 | return $numberOfBytes;
161 | }
162 |
163 | /**
164 | * @param int|string $numberOfBytes
165 | * @return int|string
166 | * @throws NegativeBytesException
167 | */
168 | private function ensureIsNotNegative($numberOfBytes)
169 | {
170 | if (bccomp($numberOfBytes, 0) < 0) {
171 | throw new NegativeBytesException();
172 | }
173 | return $numberOfBytes;
174 | }
175 |
176 | /**
177 | * @return int|string
178 | */
179 | public function numberOfBytes()
180 | {
181 | return $this->numberOfBytes;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Byte Units [](https://travis-ci.org/gabrielelana/byte-units)
2 | This is a utility component for parsing, formatting, converting and manipulating byte units in various formats.
3 |
4 | ## Usage
5 | ```php
6 | add('256B')->format('kB/0000'); // outputs 1420.2560kB
10 |
11 | // Bytes comparison
12 | ByteUnits\parse('1.2GB')->isMoreThan('256MB'); // it's true
13 | ```
14 |
15 | ### Parsing
16 | Right now two unit systems are supported:
17 | * The `Metric` system that is based on a 1000-byte kilobyte and uses standard SI suffixes (`kB`, `MB`, `GB`, `TB`, `PB`, …)
18 | * The `Binary` system that is based on a 1024-byte kilobyte and uses binary suffixes (`KiB`, `MiB`, `GiB`, `TiB`, `PiB`, …)
19 |
20 | ```php
21 | format(); // outputs 1.00kB
25 | echo ByteUnits\Binary::bytes(1024)->format(); // outputs 1.00KiB
26 |
27 | // Implicit selection through parsing
28 | ByteUnits\parse('1.00kB'); // it's an instance of ByteUnits\Metric
29 |
30 | // You can also constraint parsing to a specific system
31 | ByteUnits\Metric::parse('1.00kB'); // it's an instance of ByteUnits\Metric
32 | ByteUnits\Binary::parse('1.00kB'); // throws a ByteUnits\ParseException
33 |
34 | // For each systems there are static constructors, one for each supported unit
35 | echo ByteUnits\Metric::bytes(1000)->format(); // outputs 1.00kB
36 | echo ByteUnits\Metric::kilobytes(1)->format(); // outputs 1.00kB
37 | echo ByteUnits\Metric::megabytes(1)->format(); // outputs 1.00MB
38 |
39 | // You can switch between systems
40 | echo ByteUnits\Binary::bytes(1024)->asMetric()->format(); // outputs 1.02kB
41 | ```
42 |
43 | ### Formatting
44 | In both systems you can format bytes with an appropriate format string
45 | ```php
46 | format(); // outputs 1.32MB
50 | echo ByteUnits\bytes(132200)->format(); // outputs 132.20kB
51 |
52 | // You can force the unit using the related suffix
53 | echo ByteUnits\bytes(1322000)->format('MB'); // outputs 1.32MB
54 | echo ByteUnits\bytes(1322000)->format('kB'); // outputs 1322.00kB
55 | echo ByteUnits\bytes(1322000)->format('B'); // outputs 1322000B
56 |
57 | // You can choose the precision aka the number of digits after the `.`
58 | echo ByteUnits\bytes(1322123)->format(6); // outputs 1.322123MB
59 | echo ByteUnits\bytes(1322123)->format('/6'); // outputs 1.322123MB
60 | echo ByteUnits\bytes(1322123)->format('MB/6'); // outputs 1.322123MB
61 | echo ByteUnits\bytes(1322123)->format('MB/000000'); // outputs 1.322123MB
62 | echo ByteUnits\bytes(1322123)->format('GB/9'); // outputs 0.001322123GB
63 |
64 | // You can specify a separator between then number and the units
65 | echo ByteUnits\bytes(1322000)->format('MB', ' '); // outputs 1.32 MB
66 | echo ByteUnits\bytes(1322000)->format('MB', '/'); // outputs 1.32/MB
67 |
68 | // If you don't want to format but get the number of bytes
69 | // NOTE: The output is a string to ensure that there's no overflow
70 | echo ByteUnits\bytes(1322000)->numberOfBytes(); // outputs 1322000
71 | ```
72 |
73 | ### Compare
74 | There are a few methods that could be used to compare bytes in various units and systems
75 | ```php
76 | isLessThan(ByteUnits\Binary::kilobytes(1)); // it's true
79 | ByteUnits\Metric::kilobytes(1)->isEqualTo(ByteUnits\Binary::bytes(1000)); // it's true
80 | ByteUnits\Metric::kilobytes(1.3)->isGreaterThan(ByteUnits\Binary::kilobytes(1)); // it's true
81 | ```
82 |
83 | ### Manipulate
84 | Also you can add or remove bytes in various units and systems
85 | ```php
86 | remove(ByteUnits\Metric::kilobytes(1))->format(); // outputs 24B
89 |
90 | // Arithmetic operations always preserves the receiving unit system
91 | echo ByteUnits\Binary::kilobytes(1)->add(ByteUnits\Metric::kilobytes(1))->format(); // outputs 1.98KiB
92 |
93 | // You cannot have negative bytes
94 | ByteUnits\Metric::kilobytes(1)->remove(ByteUnits\Binary::kilobytes(1))->format(); // throws ByteUnits\NegativeBytesException
95 | ```
96 |
97 | ### Auto Boxing
98 | Most of the methods can take integers or strings and box them to appropriate byte units
99 | ```php
100 |
101 | ByteUnits\Metric::kilobytes(1)->isLessThan('1KiB'); // it's true
102 | echo ByteUnits\Binary::kilobytes(1)->remove('1KiB')->format(); // outputs 24B
103 | ```
104 |
105 | ## Installation via [Composer](http://getcomposer.org/)
106 |
107 | * Install Composer to your project root:
108 | ```bash
109 | curl -sS https://getcomposer.org/installer | php
110 | ```
111 |
112 | * Add a `composer.json` file to your project:
113 | ```json
114 | {
115 | "require": {
116 | "gabrielelana/byte-units": "^0.5"
117 | }
118 | }
119 | ```
120 |
121 | * Run the Composer installer:
122 | ```bash
123 | php composer.phar install
124 | ```
125 |
126 | ## Self-Promotion
127 | If you like this project, then consider to:
128 | * Star the repository on [GitHub](https://github.com/gabrielelana/byte-units)
129 | * Follow me on
130 | * [Twitter](http://twitter.com/gabrielelana)
131 | * [GitHub](https://github.com/gabrielelana)
132 |
--------------------------------------------------------------------------------