Skip to content

Commit

Permalink
Merge pull request #57 from mattschlosser/feat-3995-add-brotli-compre…
Browse files Browse the repository at this point in the history
…ssion

Feat 3995 add brotli compression
  • Loading branch information
christyjacob4 authored Jan 27, 2023
2 parents 7ad182d + 4195ad3 commit a77f526
Show file tree
Hide file tree
Showing 7 changed files with 1,269 additions and 3 deletions.
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RUN composer update \
FROM php:8.0-cli-alpine as compile

ENV PHP_ZSTD_VERSION="master"
ENV PHP_BROTLI_VERSION="7ae4fcd8b81a65d7521c298cae49af386d1ea4e3"
ENV PHP_SNAPPY_VERSION="bfefe4906e0abb1f6cc19005b35f9af5240d9025"
ENV PHP_LZ4_VERSION="2f006c3e4f1fb3a60d2656fc164f9ba26b71e995"

Expand All @@ -27,6 +28,7 @@ RUN apk add --no-cache \
make \
g++ \
zstd-dev \
brotli-dev \
lz4-dev

## Zstandard Extension
Expand All @@ -37,6 +39,16 @@ RUN git clone --recursive --depth 1 --branch $PHP_ZSTD_VERSION https://github.co
&& ./configure --with-libzstd \
&& make && make install


## Brotli Extension
FROM compile as brotli
RUN git clone https://github.com/kjdev/php-ext-brotli.git \
&& cd php-ext-brotli \
&& git reset --hard $PHP_BROTLI_VERSION \
&& phpize \
&& ./configure --with-libbrotli \
&& make && make install

## LZ4 Extension
FROM compile AS lz4
RUN git clone --recursive https://github.com/kjdev/php-ext-lz4.git \
Expand All @@ -62,6 +74,7 @@ LABEL maintainer="team@appwrite.io"
WORKDIR /usr/src/code

RUN echo extension=zstd.so >> /usr/local/etc/php/conf.d/zstd.ini
RUN echo extension=brotli.so >> /usr/local/etc/php/conf.d/brotli.ini
RUN echo extension=lz4.so >> /usr/local/etc/php/conf.d/lz4.ini
RUN echo extension=snappy.so >> /usr/local/etc/php/conf.d/snappy.ini

Expand All @@ -71,6 +84,7 @@ RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \

COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor
COPY --from=zstd /usr/local/lib/php/extensions/no-debug-non-zts-20200930/zstd.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=brotli /usr/local/lib/php/extensions/no-debug-non-zts-20200930/brotli.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=lz4 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/lz4.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
COPY --from=snappy /usr/local/lib/php/extensions/no-debug-non-zts-20200930/snappy.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/

Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"ext-fileinfo": "*",
"ext-zlib": "*",
"ext-zstd": "*",
"ext-brotli": "*",
"ext-lz4": "*",
"ext-snappy": "*",
"php": ">=8.0",
Expand Down
106 changes: 106 additions & 0 deletions src/Storage/Compression/Algorithms/Brotli.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace Utopia\Storage\Compression\Algorithms;

use Utopia\Storage\Compression\Compression;

class Brotli extends Compression
{
protected int $level = BROTLI_COMPRESS_LEVEL_DEFAULT;

protected int $mode = BROTLI_GENERIC;

/**
* @return string
*/
public function getName(): string
{
return 'brotli';
}

/**
* Get the compression level.
*
* @return int
*/
public function getLevel(): int
{
return $this->level;
}

/**
* Sets the brotli compression mode to generic.
*
* This is the default mode
*/
public function useGenericMode(): void
{
$this->mode = BROTLI_GENERIC;
}

/**
* Sets the brotli compression mode to UTF-8 text mode.
*
* Optimizes compression for UTF-8 formatted text
*
* @link https://github.com/kjdev/php-ext-brotli#parameters
*/
public function useTextMode(): void
{
$this->mode = BROTLI_TEXT;
}

/**
* Sets the brotli compression mode to font mode.
*
* Optimized compression for WOFF 2.0 Fonts
*
* @link https://github.com/kjdev/php-ext-brotli#parameters
*/
public function useFontMode(): void
{
$this->mode = BROTLI_FONT;
}

/**
* Set the compression level.
*
* Allow values from 0 up to a current max of 11.
*
* @param int $level
* @return void
*/
public function setLevel(int $level): void
{
$min = BROTLI_COMPRESS_LEVEL_MIN;
$max = BROTLI_COMPRESS_LEVEL_MAX;
if ($level < $min || $level > $max) {
throw new \InvalidArgumentException("Level must be between {$min} and {$max}");
}
$this->level = $level; // $level;
}

/**
* Compress.
*
* @param string $data
*
* @return string
*/
public function compress(string $data):string
{
return \brotli_compress($data, $this->getLevel(), $this->mode);
}

/**
* Decompress.
*
* @param string $data
*
* @return string
*/
public function decompress(string $data):string
{
return \brotli_uncompress($data);
}
}
108 changes: 108 additions & 0 deletions tests/Storage/Compression/Algorithms/BrotliTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace Utopia\Tests\Storage\Compression\Algorithms;

use InvalidArgumentException;
use Utopia\Storage\Compression\Algorithms\Brotli;
use PHPUnit\Framework\TestCase;

class BrotliTest extends TestCase
{
/**
* @var Brotli
*/
protected $object = null;

public function setUp(): void
{
$this->object = new Brotli();
}

public function tearDown(): void
{
}

public function testName()
{
$this->assertEquals($this->object->getName(), 'brotli');
}

public function testErrorsWhenSettingLevel()
{
$this->expectException(InvalidArgumentException::class);
$this->object->setLevel(-1);
}

public function testCompressDecompressWithText()
{
$demo = 'This is a demo string';
$demoSize = mb_strlen($demo, '8bit');

$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 21);
$this->assertEquals($dataSize, 25);

$this->assertEquals($this->object->decompress($data), $demo);
}

public function testCompressDecompressWithLargeText()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/lorem.txt');
$demoSize = mb_strlen($demo, '8bit');

$this->object->setLevel(8);
$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 386795);
$this->assertEquals($dataSize, 33128);

$this->assertGreaterThan($dataSize, $demoSize);

$data = $this->object->decompress($data);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($dataSize, 386795);
$this->assertEquals($data, $demo);
}

public function testCompressDecompressWithJPGImage()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/kitten-1.jpg');
$demoSize = mb_strlen($demo, '8bit');

$this->object->setLevel(8);
$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 599639);
// brotli is not the best for images
$this->assertEquals($dataSize, 599644);

$data = $this->object->decompress($data);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($dataSize, 599639);
}

public function testCompressDecompressWithPNGImage()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-b/kitten-1.png');
$demoSize = mb_strlen($demo, '8bit');

$this->object->setLevel(8);
$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 3038056);
// brotli is not the best for images
$this->assertEquals($dataSize, 3038068);

$data = $this->object->decompress($data);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($dataSize, 3038056);
}
}
23 changes: 21 additions & 2 deletions tests/Storage/Compression/Algorithms/GZIPTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,29 @@ public function testCompressDecompressWithText()

$this->assertEquals($demoSize, 21);
$this->assertEquals($dataSize, 39);

$this->assertEquals($this->object->decompress($data), $demo);
}


public function testCompressDecompressWithLargeText()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/lorem.txt');
$demoSize = mb_strlen($demo, '8bit');

$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 386795);
$this->assertEquals($dataSize, 44444);

$this->assertGreaterThan($dataSize, $demoSize);

$data = $this->object->decompress($data);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($dataSize, 386795);
}

public function testCompressDecompressWithJPGImage()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/kitten-1.jpg');
Expand Down
21 changes: 20 additions & 1 deletion tests/Storage/Compression/Algorithms/ZstdTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,26 @@ public function testCompressDecompressWithText()

$this->assertEquals($demo, $this->object->decompress($data));
}


public function testCompressDecompressWithLargeText()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/lorem.txt');
$demoSize = mb_strlen($demo, '8bit');

$data = $this->object->compress($demo);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($demoSize, 386795);
$this->assertEquals($dataSize, 56324);

$this->assertGreaterThan($dataSize, $demoSize);

$data = $this->object->decompress($data);
$dataSize = mb_strlen($data, '8bit');

$this->assertEquals($dataSize, 386795);
}

public function testCompressDecompressWithJPGImage()
{
$demo = \file_get_contents(__DIR__ . '/../../../resources/disk-a/kitten-1.jpg');
Expand Down
Loading

0 comments on commit a77f526

Please sign in to comment.