1
0
Fork 0
mirror of synced 2024-06-01 18:39:57 +12:00
appwrite/app/controllers/api/storage.php

619 lines
25 KiB
PHP
Raw Normal View History

2019-05-09 18:54:39 +12:00
<?php
2020-06-29 05:31:21 +12:00
use Utopia\App;
2019-05-09 18:54:39 +12:00
use Utopia\Exception;
use Utopia\Response;
2019-05-09 18:54:39 +12:00
use Utopia\Validator\ArrayList;
use Utopia\Validator\WhiteList;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\HexColor;
use Utopia\Cache\Cache;
use Utopia\Cache\Adapter\Filesystem;
use Appwrite\ClamAV\Network;
use Appwrite\Database\Database;
use Appwrite\Database\Validator\UID;
use Appwrite\Storage\Storage;
2020-06-12 07:36:10 +12:00
use Appwrite\Storage\Validator\File;
use Appwrite\Storage\Validator\FileSize;
use Appwrite\Storage\Validator\Upload;
use Appwrite\Storage\Compression\Algorithms\GZIP;
use Appwrite\Resize\Resize;
use Appwrite\OpenSSL\OpenSSL;
2020-06-30 09:43:34 +12:00
use Utopia\Config\Config;
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::post('/v1/storage/files')
2020-02-01 11:34:07 +13:00
->desc('Create File')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
2020-02-01 11:34:07 +13:00
->label('scope', 'files.write')
->label('webhook', 'storage.files.create')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'createFile')
->label('sdk.description', '/docs/references/storage/create-file.md')
->label('sdk.consumes', 'multipart/form-data')
2020-04-11 06:59:14 +12:00
->label('sdk.methodType', 'upload')
2020-09-11 02:40:14 +12:00
->param('file', [], new File(), 'Binary file.', false)
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
2020-07-06 02:19:59 +12:00
->action(function ($file, $read, $write, $request, $response, $user, $projectDB, $webhooks, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 09:43:34 +12:00
/** @var Appwrite\Database\Document $user */
/** @var Appwrite\Database\Database $projectDB */
2020-07-06 02:19:59 +12:00
/** @var Appwrite\Event\Event $webhooks */
/** @var Appwrite\Event\Event $audits */
2020-06-30 09:43:34 +12:00
/** @var Appwrite\Event\Event $usage */
$file = $request->getFiles('file');
$read = (empty($read)) ? ['user:'.$user->getId()] : $read;
$write = (empty($write)) ? ['user:'.$user->getId()] : $write;
/*
* Validators
*/
//$fileType = new FileType(array(FileType::FILE_TYPE_PNG, FileType::FILE_TYPE_GIF, FileType::FILE_TYPE_JPEG));
$fileSize = new FileSize(App::getEnv('_APP_STORAGE_LIMIT', 0));
$upload = new Upload();
if (empty($file)) {
throw new Exception('No file sent', 400);
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
// Make sure we handle a single file and multiple files the same way
$file['name'] = (\is_array($file['name']) && isset($file['name'][0])) ? $file['name'][0] : $file['name'];
$file['tmp_name'] = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name'];
$file['size'] = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
// Check if file type is allowed (feature for project settings?)
//if (!$fileType->isValid($file['tmp_name'])) {
//throw new Exception('File type not allowed', 400);
//}
2020-02-01 11:34:07 +13:00
2020-07-11 16:17:45 +12:00
if (!$fileSize->isValid($file['size'])) { // Check if file size is exceeding allowed limit
2020-06-30 09:43:34 +12:00
throw new Exception('File size not allowed', 400);
}
2020-02-01 11:34:07 +13:00
2020-07-15 09:20:46 +12:00
$device = Storage::getDevice('files');
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
if (!$upload->isValid($file['tmp_name'])) {
throw new Exception('Invalid file', 403);
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
// Save to storage
$size = $device->getFileSize($file['tmp_name']);
$path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION));
if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move'
throw new Exception('Failed moving file', 500);
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
$mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled
$antiVirus = new Network('clamav', 3310);
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
if (!$antiVirus->fileScan($path)) {
$device->delete($path);
throw new Exception('Invalid file', 403);
2020-02-01 11:34:07 +13:00
}
2020-06-30 09:43:34 +12:00
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
// Compression
$compressor = new GZIP();
$data = $device->read($path);
$data = $compressor->compress($data);
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
if (!$device->write($path, $data)) {
throw new Exception('Failed to save file', 500);
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
$sizeActual = $device->getFileSize($path);
$file = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'read' => $read,
'write' => $write,
],
'dateCreated' => \time(),
'folderId' => '',
'name' => $file['name'],
'path' => $path,
'signature' => $device->getFileHash($path),
'mimeType' => $mimeType,
'sizeOriginal' => $size,
'sizeActual' => $sizeActual,
'algorithm' => $compressor->getName(),
'token' => \bin2hex(\random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion' => '1',
'fileOpenSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'fileOpenSSLTag' => \bin2hex($tag),
'fileOpenSSLIV' => \bin2hex($iv),
]);
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
2020-02-01 11:34:07 +13:00
2020-07-06 02:19:59 +12:00
$webhooks
2020-06-30 09:43:34 +12:00
->setParam('payload', $file->getArrayCopy())
;
2020-02-01 11:34:07 +13:00
2020-07-06 02:19:59 +12:00
$audits
2020-06-30 09:43:34 +12:00
->setParam('event', 'storage.files.create')
->setParam('resource', 'storage/files/'.$file->getId())
;
$usage
->setParam('storage', $sizeActual)
;
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($file->getArrayCopy())
;
2020-07-06 02:19:59 +12:00
}, ['request', 'response', 'user', 'projectDB', 'webhooks', 'audits', 'usage']);
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/storage/files')
2019-05-09 18:54:39 +12:00
->desc('List Files')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
->label('scope', 'files.read')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'listFiles')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/list-files.md')
2020-09-11 02:40:14 +12:00
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
2020-06-30 09:43:34 +12:00
->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 09:43:34 +12:00
/** @var Appwrite\Database\Database $projectDB */
$results = $projectDB->getCollection([
'limit' => $limit,
'offset' => $offset,
'orderField' => 'dateCreated',
'orderType' => $orderType,
'orderCast' => 'int',
'search' => $search,
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_FILES,
],
]);
$results = \array_map(function ($value) { /* @var $value \Database\Document */
return $value->getArrayCopy(['$id', '$permissions', 'name', 'dateCreated', 'signature', 'mimeType', 'sizeOriginal']);
}, $results);
$response->json(['sum' => $projectDB->getSum(), 'files' => $results]);
}, ['response', 'projectDB']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::get('/v1/storage/files/:fileId')
2019-05-09 18:54:39 +12:00
->desc('Get File')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
->label('scope', 'files.read')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'getFile')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/get-file.md')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID.')
2020-06-30 09:43:34 +12:00
->action(function ($fileId, $response, $projectDB) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 09:43:34 +12:00
/** @var Appwrite\Database\Database $projectDB */
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$file = $projectDB->getDocument($fileId);
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
2019-05-09 18:54:39 +12:00
}
2020-06-30 09:43:34 +12:00
$response->json($file->getArrayCopy(['$id', '$permissions', 'name', 'dateCreated', 'signature', 'mimeType', 'sizeOriginal']));
}, ['response', 'projectDB']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::get('/v1/storage/files/:fileId/preview')
2019-08-25 20:10:28 +12:00
->desc('Get File Preview')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
->label('scope', 'files.read')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'getFilePreview')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/get-file-preview.md')
2020-01-15 05:16:24 +13:00
->label('sdk.response.type', 'image/*')
2020-04-11 06:59:14 +12:00
->label('sdk.methodType', 'location')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID')
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
->param('background', '', new HexColor(), 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
2020-06-30 23:09:28 +12:00
->action(function ($fileId, $width, $height, $quality, $background, $output, $request, $response, $project, $projectDB) {
/** @var Utopia\Swoole\Request $request */
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Database $projectDB */
2019-05-09 18:54:39 +12:00
2020-07-15 09:20:46 +12:00
$storage = 'files';
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!\extension_loaded('imagick')) {
throw new Exception('Imagick extension is missing', 500);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!Storage::exists($storage)) {
throw new Exception('No such storage device', 400);
}
2020-07-04 03:14:51 +12:00
if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' == $output)) { // Fallback webp to jpeg when no browser support
2020-06-30 23:09:28 +12:00
$output = 'jpg';
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$inputs = Config::getParam('storage-inputs');
$outputs = Config::getParam('storage-outputs');
$fileLogos = Config::getParam('storage-logos');
2020-06-30 16:32:36 +12:00
2020-06-30 23:09:28 +12:00
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = \md5($fileId.$width.$height.$quality.$background.$storage.$output);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$file = $projectDB->getDocument($fileId);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$path = $file->getAttribute('path');
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
$algorithm = $file->getAttribute('algorithm');
$cipher = $file->getAttribute('fileOpenSSLCipher');
$mime = $file->getAttribute('mimeType');
if (!\in_array($mime, $inputs)) {
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
$algorithm = null;
$cipher = null;
$background = (empty($background)) ? 'eceff1' : $background;
2020-06-20 23:20:49 +12:00
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
2020-06-30 23:09:28 +12:00
$key = \md5($path.$width.$height.$quality.$background.$storage.$output);
}
2019-05-12 16:56:55 +12:00
2020-06-30 23:09:28 +12:00
$compressor = new GZIP();
2020-07-15 09:20:46 +12:00
$device = Storage::getDevice('files');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!\file_exists($path)) {
throw new Exception('File not found', 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$cache = new Cache(new Filesystem(APP_STORAGE_CACHE.'/app-'.$project->getId())); // Limit file number or size
$data = $cache->load($key, 60 * 60 * 24 * 30 * 3 /* 3 months */);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if ($data) {
$output = (empty($output)) ? $type : $output;
2019-05-09 18:54:39 +12:00
2020-07-03 15:11:16 +12:00
return $response
2020-07-03 21:11:19 +12:00
->setContentType((\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'])
2020-06-30 23:09:28 +12:00
->addHeader('Expires', $date)
->addHeader('X-Appwrite-Cache', 'hit')
->send($data)
;
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$source = $device->read($path);
if (!empty($cipher)) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!empty($algorithm)) {
$source = $compressor->decompress($source);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$resize = new Resize($source);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$resize->crop((int) $width, (int) $height);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!empty($background)) {
$resize->setBackground('#'.$background);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$output = (empty($output)) ? $type : $output;
2019-05-09 18:54:39 +12:00
2020-07-03 15:11:16 +12:00
$data = $resize->output($output, $quality);
$cache->save($key, $data);
2020-06-30 23:09:28 +12:00
$response
->setContentType($outputs[$output])
->addHeader('Expires', $date)
->addHeader('X-Appwrite-Cache', 'miss')
2020-07-03 15:11:16 +12:00
->send($data)
2020-06-30 23:09:28 +12:00
;
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
unset($resize);
}, ['request', 'response', 'project', 'projectDB']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::get('/v1/storage/files/:fileId/download')
2019-08-25 20:10:28 +12:00
->desc('Get File for Download')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
->label('scope', 'files.read')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'getFileDownload')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/get-file-download.md')
2020-01-15 05:16:24 +13:00
->label('sdk.response.type', '*')
2020-04-11 06:59:14 +12:00
->label('sdk.methodType', 'location')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID.')
2020-06-30 23:09:28 +12:00
->action(function ($fileId, $response, $projectDB) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Database\Database $projectDB */
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$file = $projectDB->getDocument($fileId);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$path = $file->getAttribute('path', '');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!\file_exists($path)) {
throw new Exception('File not found in '.$path, 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$compressor = new GZIP();
2020-07-15 09:20:46 +12:00
$device = Storage::getDevice('files');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$source = $device->read($path);
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$source = $compressor->decompress($source);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
// Response
$response
->setContentType($file->getAttribute('mimeType'))
->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"')
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->addHeader('X-Peak', \memory_get_peak_usage())
->send($source)
;
}, ['response', 'projectDB']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::get('/v1/storage/files/:fileId/view')
2019-08-25 20:10:28 +12:00
->desc('Get File for View')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
->label('scope', 'files.read')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'getFileView')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/get-file-view.md')
2020-01-15 05:16:24 +13:00
->label('sdk.response.type', '*')
2020-04-11 06:59:14 +12:00
->label('sdk.methodType', 'location')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID.')
->param('as', '', new WhiteList(['pdf', /*'html',*/ 'text'], true), 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true)
2020-06-30 23:09:28 +12:00
->action(function ($fileId, $as, $response, $projectDB) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Database\Database $projectDB */
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$file = $projectDB->getDocument($fileId);
$mimes = Config::getParam('storage-mimes');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$path = $file->getAttribute('path', '');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (!\file_exists($path)) {
throw new Exception('File not found in '.$path, 404);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$compressor = new GZIP();
2020-07-15 09:20:46 +12:00
$device = Storage::getDevice('files');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$contentType = 'text/plain';
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (\in_array($file->getAttribute('mimeType'), $mimes)) {
$contentType = $file->getAttribute('mimeType');
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$source = $device->read($path);
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
);
}
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$output = $compressor->decompress($source);
$fileName = $file->getAttribute('name', '');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$contentTypes = [
'pdf' => 'application/pdf',
'text' => 'text/plain',
];
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$contentType = (\array_key_exists($as, $contentTypes)) ? $contentTypes[$as] : $contentType;
// Response
$response
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="'.$fileName.'"')
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->addHeader('X-Peak', \memory_get_peak_usage())
->send($output)
;
}, ['response', 'projectDB']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App::put('/v1/storage/files/:fileId')
2019-08-29 00:29:45 +12:00
->desc('Update File')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
2019-08-29 00:29:45 +12:00
->label('scope', 'files.write')
->label('webhook', 'storage.files.update')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-08-29 00:29:45 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'updateFile')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/update-file.md')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID.')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
2020-07-06 02:19:59 +12:00
->action(function ($fileId, $read, $write, $response, $projectDB, $webhooks, $audits) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Database\Database $projectDB */
2020-07-06 02:19:59 +12:00
/** @var Appwrite\Event\Event $webhooks */
/** @var Appwrite\Event\Event $audits */
2019-08-29 00:29:45 +12:00
2020-06-30 23:09:28 +12:00
$file = $projectDB->getDocument($fileId);
2019-08-29 00:29:45 +12:00
2020-06-30 23:09:28 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
2019-08-29 00:29:45 +12:00
2020-06-30 23:09:28 +12:00
$file = $projectDB->updateDocument(\array_merge($file->getArrayCopy(), [
'$permissions' => [
'read' => $read,
'write' => $write,
],
'folderId' => '',
]));
2019-08-29 00:29:45 +12:00
2020-06-30 23:09:28 +12:00
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
2020-07-06 02:19:59 +12:00
$webhooks
2020-06-30 23:09:28 +12:00
->setParam('payload', $file->getArrayCopy())
;
2020-07-06 02:19:59 +12:00
$audits
2020-06-30 23:09:28 +12:00
->setParam('event', 'storage.files.update')
->setParam('resource', 'storage/files/'.$file->getId())
;
$response->json($file->getArrayCopy());
2020-07-06 02:19:59 +12:00
}, ['response', 'projectDB', 'webhooks', 'audits']);
2019-08-29 00:29:45 +12:00
2020-06-29 05:31:21 +12:00
App::delete('/v1/storage/files/:fileId')
2019-05-09 18:54:39 +12:00
->desc('Delete File')
2020-06-26 06:32:12 +12:00
->groups(['api', 'storage'])
2019-08-14 23:53:07 +12:00
->label('scope', 'files.write')
->label('webhook', 'storage.files.delete')
2020-01-27 19:14:14 +13:00
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
2019-05-09 18:54:39 +12:00
->label('sdk.namespace', 'storage')
2020-01-31 09:58:49 +13:00
->label('sdk.method', 'deleteFile')
2019-10-08 20:09:35 +13:00
->label('sdk.description', '/docs/references/storage/delete-file.md')
2020-09-11 02:40:14 +12:00
->param('fileId', '', new UID(), 'File unique ID.')
2020-07-06 02:19:59 +12:00
->action(function ($fileId, $response, $projectDB, $webhooks, $audits, $usage) {
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Database\Database $projectDB */
2020-07-06 02:19:59 +12:00
/** @var Appwrite\Event\Event $webhooks */
/** @var Appwrite\Event\Event $audits */
2020-06-30 23:09:28 +12:00
/** @var Appwrite\Event\Event $usage */
$file = $projectDB->getDocument($fileId);
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
throw new Exception('File not found', 404);
}
2019-05-09 18:54:39 +12:00
2020-07-15 09:20:46 +12:00
$device = Storage::getDevice('files');
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
if ($device->delete($file->getAttribute('path', ''))) {
if (!$projectDB->deleteDocument($fileId)) {
throw new Exception('Failed to remove file from DB', 500);
2019-05-09 18:54:39 +12:00
}
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2020-07-06 02:19:59 +12:00
$webhooks
2020-06-30 23:09:28 +12:00
->setParam('payload', $file->getArrayCopy())
;
2020-07-06 02:19:59 +12:00
$audits
2020-06-30 23:09:28 +12:00
->setParam('event', 'storage.files.delete')
->setParam('resource', 'storage/files/'.$file->getId())
;
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$usage
->setParam('storage', $file->getAttribute('size', 0) * -1)
;
2019-05-09 18:54:39 +12:00
2020-06-30 23:09:28 +12:00
$response->noContent();
2020-07-06 02:19:59 +12:00
}, ['response', 'projectDB', 'webhooks', 'audits', 'usage']);
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
// App::get('/v1/storage/files/:fileId/scan')
// ->desc('Scan Storage')
2020-06-26 06:32:12 +12:00
// ->groups(['api', 'storage'])
// ->label('scope', 'god')
// ->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
// ->label('sdk.namespace', 'storage')
// ->label('sdk.method', 'getFileScan')
// ->label('sdk.hide', true)
2020-09-11 02:40:14 +12:00
// ->param('fileId', '', new UID(), 'File unique ID.')
// ->param('storage', 'files', new WhiteList(['files']);})
// ->action(
// function ($fileId, $storage) use ($response, $request, $projectDB) {
// $file = $projectDB->getDocument($fileId);
// if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
// throw new Exception('File not found', 404);
// }
// $path = $file->getAttribute('path', '');
// if (!file_exists($path)) {
// throw new Exception('File not found in '.$path, 404);
// }
// $compressor = new GZIP();
// $device = Storage::getDevice($storage);
// $source = $device->read($path);
// if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
// $source = OpenSSL::decrypt(
// $source,
// $file->getAttribute('fileOpenSSLCipher'),
2020-06-29 08:45:36 +12:00
// App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
// 0,
// hex2bin($file->getAttribute('fileOpenSSLIV')),
// hex2bin($file->getAttribute('fileOpenSSLTag'))
// );
// }
// $source = $compressor->decompress($source);
// $antiVirus = new Network('clamav', 3310);
// //var_dump($antiVirus->ping());
// //var_dump($antiVirus->version());
// //var_dump($antiVirus->fileScan('/storage/uploads/app-1/5/9/f/e/59fecaed49645.pdf'));
// //$response->json($antiVirus->continueScan($device->getRoot()));
// }
// );