summaryrefslogtreecommitdiffstats
path: root/application/service/storage.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/service/storage.php')
-rw-r--r--application/service/storage.php160
1 files changed, 160 insertions, 0 deletions
diff --git a/application/service/storage.php b/application/service/storage.php
new file mode 100644
index 000000000..b2c2abca7
--- /dev/null
+++ b/application/service/storage.php
@@ -0,0 +1,160 @@
+<?php
+/*
+ * Copyright 2014 Florian "Bluewind" Pritz <bluewind@server-speed.net>
+ *
+ * Licensed under AGPLv3
+ * (see COPYING for full license text)
+ *
+ */
+
+namespace service;
+
+/**
+ * This class allows to change a temporary file and replace the original one atomically
+ */
+class storage {
+ private $path;
+ private $tempfile = NULL;
+
+ public function __construct($path)
+ {
+ assert(!is_dir($path));
+
+ $this->path = $path;
+ }
+
+ /**
+ * Create a temp file which can be written to.
+ *
+ * Call commit() once you are done writing.
+ * Call rollback() to remove the file and throw away any data written.
+ *
+ * Calling this multiple times will automatically rollback previous calls.
+ *
+ * @return temp file path
+ */
+ public function begin()
+ {
+ if($this->tempfile !== NULL) {
+ $this->rollback();
+ }
+
+ $this->tempfile = $this->create_tempfile();
+
+ return $this->tempfile;
+ }
+
+ /**
+ * Create a temporary file. You'll need to remove it yourself when no longer needed.
+ *
+ * @return path to the temporary file
+ */
+ private function create_tempfile()
+ {
+ $dir = dirname($this->get_file());
+ $prefix = basename($this->get_file());
+
+ if (!is_dir($dir)) {
+ mkdir($dir, 0777, true);
+ }
+ assert(is_dir($dir));
+
+ return tempnam($dir, $prefix);
+ }
+
+ /**
+ * Save the temporary file returned by begin() to the permanent path
+ * (supplied to the constructor) in an atomic fashion.
+ */
+ public function commit()
+ {
+ $ret = rename($this->tempfile, $this->get_file());
+ if ($ret) {
+ $this->tempfile = NULL;
+ }
+
+ return $ret;
+ }
+
+ public function exists()
+ {
+ return file_exists($this->get_file());
+ }
+
+ public function get_file()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Throw away any changes made to the temporary file returned by begin()
+ */
+ public function rollback()
+ {
+ if ($this->tempfile !== NULL) {
+ unlink($this->tempfile);
+ $this->tempfile = NULL;
+ }
+ }
+
+ public function __destruct()
+ {
+ $this->rollback();
+ }
+
+ /**
+ * GZIPs the temp file
+ *
+ * From http://stackoverflow.com/questions/6073397/how-do-you-create-a-gz-file-using-php
+ * Based on function by Kioob at:
+ * http://www.php.net/manual/en/function.gzwrite.php#34955
+ *
+ * @param integer $level GZIP compression level (default: 6)
+ * @return boolean true if operation succeeds, false on error
+ */
+ public function gzip_compress($level = 6){
+ if ($this->tempfile === NULL) {
+ return;
+ }
+
+ $source = $this->tempfile;
+ $file = new storage($source);
+ $dest = $file->begin();
+ $mode = 'wb' . $level;
+ $error = false;
+ $chunk_size = 1024*512;
+
+ if ($fp_out = gzopen($dest, $mode)) {
+ if ($fp_in = fopen($source,'rb')) {
+ while (!feof($fp_in)) {
+ gzwrite($fp_out, fread($fp_in, $chunk_size));
+ }
+ fclose($fp_in);
+ } else {
+ $error = true;
+ }
+ gzclose($fp_out);
+ } else {
+ $error = true;
+ }
+
+ if ($error) {
+ return false;
+ } else {
+ $file->commit();
+ return true;
+ }
+ }
+
+ /**
+ * Delete the file if it exists.
+ */
+ public function unlink()
+ {
+ if ($this->exists()) {
+ unlink($this->get_file());
+ }
+ }
+}
+
+# vim: set noet: