From fb50f23e194732779b487bd17b7ba9d913a24ead Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 10 Jan 2020 14:25:26 +0100 Subject: [PATCH] added new storage controller (FTP) and updated config --- inc/core.php | 22 ++++++-- rtfm/CONFIG.md | 40 +++++++++++-- storage-controllers/ftp.controller.php | 78 ++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 storage-controllers/ftp.controller.php diff --git a/inc/core.php b/inc/core.php index efc693d..0cbd1aa 100644 --- a/inc/core.php +++ b/inc/core.php @@ -49,12 +49,14 @@ function architect($url) if(!$sc) $sc = getStorageControllers(); foreach($sc as $contr) - { + { $c = new $contr(); + if($c->isEnabled()===true && $c->hashExists($el)) { $hash = $el; $c->pullFile($hash,ROOT.DS.'tmp'.DS.$hash); + if(!file_exists(ROOT.DS.'tmp'.DS.$hash)) continue; storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true); break; // we break here because we already have the file. no need to check other storage controllers @@ -63,7 +65,7 @@ function architect($url) { $hash = $el.'.enc'; $c->pullFile($hash,ROOT.DS.'tmp'.DS.$hash); - + if(!file_exists(ROOT.DS.'tmp'.DS.$hash)) continue; $enc = new Encryption; $hash = substr($hash,0,-4); $enc->decryptFile(ROOT.DS.'tmp'.DS.$el.'.enc', ROOT.DS.'tmp'.DS.$hash,base64_decode(ENCRYPTION_KEY)); @@ -488,6 +490,7 @@ function getAllContentFiletypes() } function rrmdir($dir) { + chmod($dir, 0777); if (is_dir($dir)) { $objects = scandir($dir); foreach ($objects as $object) { @@ -495,7 +498,9 @@ function rrmdir($dir) { if (is_dir($dir."/".$object)) rrmdir($dir."/".$object); else + { unlink($dir."/".$object); + } } } rmdir($dir); @@ -530,12 +535,16 @@ function storeFile($srcfile,$hash,$deleteoriginal=false) function getDeleteCodeOfHash($hash) { - return file_get_contents(ROOT.DS.'data'.DS.$hash.DS.'deletecode'); + if(file_exists(ROOT.DS.'data'.DS.$hash.DS.'deletecode')) + return file_get_contents(ROOT.DS.'data'.DS.$hash.DS.'deletecode'); + return false; } function deleteHash($hash) { - //delete all local images + //@todo: add hash to deleted list. also on all controllers + + //delete all files in directory rrmdir(ROOT.DS.'data'.DS.$hash); //tell every storage controller to delete theirs as well @@ -547,6 +556,11 @@ function deleteHash($hash) { $c->deleteFile($hash); } + //delete encrypted file if it exists + if($c->isEnabled()===true && defined('ENCRYPTION_KEY') && ENCRYPTION_KEY !='' && $c->hashExists($hash.'.enc')) + { + $c->deleteFile($hash.'.enc'); + } } } diff --git a/rtfm/CONFIG.md b/rtfm/CONFIG.md index a8036e5..3ca6b95 100644 --- a/rtfm/CONFIG.md +++ b/rtfm/CONFIG.md @@ -24,13 +24,43 @@ In this file you can set the following options. For a simple working example con # Storage controllers -PictShare has an extention system that allows handling of multiple storage solutions or backends. You can configure them with the following settings +PictShare has an extention system that allows handling of multiple storage solutions or backends. If a requested file is not found locally, PictShare will ask all configured storage controllers if they have it, then download and serve it to the user. + +If you want data on your external storage to be **encrypted**, you can set the following config setting. En/decryption is done automatically on up/download. |Option | value type | What it does| |--- | --- | ---| |ENCRYPTION_KEY | base64 string | The key used to encrypt/decrypt files stored in storage controllers. See [/rtfm/ENCRYPTION.md](/rtfm/ENCRYPTION.md) for setup guide | + + +## Alternative Folder + +The ALT_FOLDER option will copy every uploaded file from PictShare to a local path of your choice. This can be used to keep two allow two instances of PictShare to serve the same data. Eg. you can mount a NFS on your server and configure the ALT_FOLDER variable to point to that folder. All images are then stored on the NFS as well as your PictShare server. + +|Option | value type | What it does| +|--- | --- | ---| | ALT_FOLDER | string | All uploaded files will be copied to this location. This location can be a mounted network share (eg NFS or FTP, etc). If a file is not found in the normal upload direcotry, ALT_FOLDER will be checked. [more info about scaling PictShare](/rtfm/SCALING.md) | -|S3_BUCKET | string | Name of your [S3 bucket](https://aws.amazon.com/s3/) | -|S3_ACCESS_KEY | string | Access key for your bucket| -|S3_SECRET_KEY | string | Secret key for your bucket -|S3_ENDPOINT | URL | Server URL. If you're using S3 compatible software like [Minio](https://min.io/) you can enter the URL here | + + +## S3 (compatible) storage + +You can also store all uploaded files on S3 or S3 compatible storage like [Minio](https://min.io/). This can also be used to scale your PictShare instance and have multiple distributed servers server the same files. + +|Option | value type | What it does| +|--- | --- | ---| +|S3_BUCKET | string | Name of your [S3 bucket](https://aws.amazon.com/s3/) | +|S3_ACCESS_KEY | string | Access key for your bucket| +|S3_SECRET_KEY | string | Secret key for your bucket | +|S3_ENDPOINT | URL | Server URL. If you're using S3 compatible software like [Minio](https://min.io/) you can enter the URL here | + +## FTP + +Oldschool, insecure and not that fast. But if you use it in combination with [/rtfm/ENCRYPTION.md](Encryption) this could be OK I guess. I don't judge. +This probably requires the php-ftp package but on some platforms it's included in the php-common package. + +|Option | value type | What it does| +|--- | --- | ---| +|FTP_SERVER | string | IP or hostname of your FTP Server | +|FTP_USER | string | FTP Username | +|FTP_PASS | string | FTP Password | +|FTP_BASEDIR | string | Base path where files will be stored. Must end with / eg `/web/pictshare/` | diff --git a/storage-controllers/ftp.controller.php b/storage-controllers/ftp.controller.php new file mode 100644 index 0000000..4f596a5 --- /dev/null +++ b/storage-controllers/ftp.controller.php @@ -0,0 +1,78 @@ +connection) + ftp_close($this->connection); + } + + function connect() + { + if(!$this->connection) + $this->connection = ftp_connect(FTP_SERVER); + if(!$this->login) + $this->login = ftp_login($this->connection, FTP_USER, FTP_PASS); + + // Was the connection successful? + if ((!$this->connection) || (!$this->login)) { + $this->connection = false; + return false; + } + return true; + } + + function isEnabled() + { + return (defined('FTP_SERVER') && FTP_SERVER && + defined('FTP_USER') && FTP_USER && + defined('FTP_PASS') && FTP_PASS); + } + + function hashExists($hash) + { + if(!$this->connect()) return null; + $ftpfilepath = FTP_BASEDIR.$hash; + return (ftp_size($this->connection,$ftpfilepath)>0?true:false); + } + + function getItems($dev=false) + { + if(!$this->connect()) return false; + $list = array(); + $files = ftp_mlsd($this->connection,FTP_BASEDIR); + foreach ($files as $filearray) + { + $filename = $filearray['name']; + if($filearray['type']=='dir' || startsWith($filename,'.') || !mightBeAHash($filename)) continue; + $list[] = $filename; + } + + return $list; + } + + function pullFile($hash,$location) + { + if(!$this->connect()) return false; + $ftpfilepath = FTP_BASEDIR.$hash; + return ftp_get($this->connection, $location, $ftpfilepath, FTP_BINARY); + } + + function pushFile($source,$hash) + { + if(!$this->connect()) return false; + $ftpfilepath = FTP_BASEDIR.$hash; + return ftp_put($this->connection, $ftpfilepath, $source, FTP_BINARY); + } + + function deleteFile($hash) + { + if(!$this->connect()) return false; + $ftpfilepath = FTP_BASEDIR.$hash; + return (ftp_delete($this->connection,$ftpfilepath)?true:false); + } +} \ No newline at end of file