summaryrefslogtreecommitdiffstats
path: root/preload-zstd.inc
diff options
context:
space:
mode:
Diffstat (limited to 'preload-zstd.inc')
-rw-r--r--preload-zstd.inc89
1 files changed, 89 insertions, 0 deletions
diff --git a/preload-zstd.inc b/preload-zstd.inc
new file mode 100644
index 0000000..de8abd0
--- /dev/null
+++ b/preload-zstd.inc
@@ -0,0 +1,89 @@
+<?php
+/**
+ * ZSTD compressor using FFI and libzstd
+ * PoC, only for documentation purpose
+ *
+ * Copyright (c) 2019 Remi Collet
+ * License: CC-BY-SA
+ * http://creativecommons.org/licenses/by-sa/4.0/
+ */
+namespace Remi;
+
+class Zstd {
+ static private $ffi = null;
+
+ public static function init() {
+ if (self::$ffi) {
+ return;
+ }
+ // Try if preloaded
+ try {
+ self::$ffi = \FFI::scope("_REMI_ZSTD_");
+ } catch (\FFI\Exception $e) {
+ // Try direct load
+ if (PHP_SAPI === 'cli' || (int)ini_get("ffi.enable")) {
+ self::$ffi = \FFI::load(__DIR__ . '/preload-zstd.h');
+ } else {
+ throw $e;
+ }
+ }
+ if (!self::$ffi) {
+ throw new \RuntimeException("FFI parse fails");
+ }
+ }
+
+ public static function compress($in, $out) {
+ self::init();
+
+ $ret = [];
+ $src = file_get_contents($in);
+ if ($src === false) {
+ throw new \RuntimeException("Read fails");
+ }
+ $len = strlen($src);
+ $ret['in_len'] = $len;
+
+ $max = self::$ffi->ZSTD_compressBound($len);
+ $ret['max_len'] = $max;
+
+ $comp = str_repeat(' ', $max);
+ $clen = self::$ffi->ZSTD_compress($comp, $max, $src, $len, 6);
+ if (self::$ffi->ZSTD_isError($clen)) {
+ throw new \RuntimeException("Compression fails");
+ }
+ $ret['out_len'] = $clen;
+ if (file_put_contents($out, substr($comp, 0, $clen)) !== $clen) {
+ throw new \RuntimeException("Save fails");
+ }
+
+ return $ret;
+ }
+
+ public static function decompress($in, $out) {
+ self::init();
+
+ $ret = [];
+ $comp = file_get_contents($in);
+ if ($comp === false) {
+ throw new \RuntimeException("Read fails");
+ }
+ $clen = strlen($comp);
+ $ret['in_len'] = $clen;
+
+ $max = self::$ffi->ZSTD_decompressBound($comp, $clen);
+ $ret['max_len'] = $max;
+
+ $unco = str_repeat(' ', $max);
+ $ulen = self::$ffi->ZSTD_decompress($unco, $max, $comp, $clen);
+ if (self::$ffi->ZSTD_isError($clen)) {
+ throw new \RuntimeException("Compression fails");
+ }
+ $ret['out_len'] = $ulen;
+ if (file_put_contents($out, substr($unco, 0, $ulen)) !== $ulen) {
+ throw new \RuntimeException("Save fails");
+ }
+
+ return $ret;
+ }
+}
+