From fc2b804cccadcd2e9f90953f02b5977b2eb46439 Mon Sep 17 00:00:00 2001 From: fabrixxm <fabrix.xm@gmail.com> Date: Wed, 2 Jan 2019 15:13:05 +0100 Subject: [PATCH] Move mod/attach to src, add Attach model, update attach table to use storage backends --- config/dbstructure.config.php | 4 +- mod/attach.php | 54 ------------ src/Model/Attach.php | 152 ++++++++++++++++++++++++++++++++++ src/Module/Attach.php | 67 +++++++++++++++ 4 files changed, 222 insertions(+), 55 deletions(-) delete mode 100644 mod/attach.php create mode 100644 src/Model/Attach.php create mode 100644 src/Module/Attach.php diff --git a/config/dbstructure.config.php b/config/dbstructure.config.php index 0be6ba4028..a4728c15d1 100644 --- a/config/dbstructure.config.php +++ b/config/dbstructure.config.php @@ -34,7 +34,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1298); + define('DB_UPDATE_VERSION', 1299); } return [ @@ -99,6 +99,8 @@ return [ "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], + "backend-class" => ["type" => "tinytext", "comment" => "Storage backend class"], + "backend-ref" => ["type" => "text", "comment" => "Storage backend data reference"], ], "indexes" => [ "PRIMARY" => ["id"], diff --git a/mod/attach.php b/mod/attach.php deleted file mode 100644 index f3192d802d..0000000000 --- a/mod/attach.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * @file mod/attach.php - */ - -use Friendica\App; -use Friendica\Core\L10n; -use Friendica\Database\DBA; -use Friendica\Util\Security; - -function attach_init(App $a) -{ - if ($a->argc != 2) { - notice(L10n::t('Item not available.') . EOL); - return; - } - - $item_id = intval($a->argv[1]); - - // Check for existence, which will also provide us the owner uid - - $r = DBA::selectFirst('attach', [], ['id' => $item_id]); - if (!DBA::isResult($r)) { - notice(L10n::t('Item was not found.'). EOL); - return; - } - - $sql_extra = Security::getPermissionsSQLByUserId($r['uid']); - - // Now we'll see if we can access the attachment - - $r = q("SELECT * FROM `attach` WHERE `id` = '%d' $sql_extra LIMIT 1", - DBA::escape($item_id) - ); - - if (!DBA::isResult($r)) { - notice(L10n::t('Permission denied.') . EOL); - return; - } - - // Use quotes around the filename to prevent a "multiple Content-Disposition" - // error in Chrome for filenames with commas in them - header('Content-type: ' . $r[0]['filetype']); - header('Content-length: ' . $r[0]['filesize']); - if (isset($_GET['attachment']) && $_GET['attachment'] === '0') { - header('Content-disposition: filename="' . $r[0]['filename'] . '"'); - } else { - header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"'); - } - - echo $r[0]['data']; - exit(); - // NOTREACHED -} diff --git a/src/Model/Attach.php b/src/Model/Attach.php new file mode 100644 index 0000000000..13b0adb6f2 --- /dev/null +++ b/src/Model/Attach.php @@ -0,0 +1,152 @@ +<?php + +/** + * @file src/Model/Attach.php + * @brief This file contains the Attach class for database interface + */ +namespace Friendica\Model; + +use Friendica\BaseObject; +use Friendica\Core\StorageManager; +use Friendica\Database\DBA; +use Friendica\Database\DBStructure; +use Friendica\Util\Security; + + +/** + * Class to handle attach dabatase table + */ +class Attach extends BaseObject +{ + + /** + * @brief Return a list of fields that are associated with the attach table + * + * @return array field list + */ + private static function getFields() + { + $allfields = DBStructure::definition(false); + $fields = array_keys($allfields['attach']['fields']); + array_splice($fields, array_search('data', $fields), 1); + return $fields; + } + + /** + * @brief Select rows from the attach table + * + * @param array $fields Array of selected fields, empty for all + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters + * + * @return boolean|array + * + * @see \Friendica\Database\DBA::select + */ + public static function select(array $fields = [], array $conditions = [], array $params = []) + { + if (empty($fields)) { + $selected = self::getFields(); + } + + $r = DBA::select('attach', $fields, $conditions, $params); + return DBA::toArray($r); + } + + /** + * @brief Retrieve a single record from the attach table + * + * @param array $fields Array of selected fields, empty for all + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters + * + * @return bool|array + * + * @see \Friendica\Database\DBA::select + */ + public static function selectFirst(array $fields = [], array $conditions = [], array $params = []) + { + if (empty($fields)) { + $fields = self::getFields(); + } + + return DBA::selectFirst('attach', $fields, $conditions, $params); + } + + /** + * @brief Check if attachment with given conditions exists + * + * @param array $conditions Array of extra conditions + * + * @return boolean + */ + public static function exists(array $conditions) + { + return DBA::exists('attach', $conditions); + } + + /** + * @brief Retrive a single record given the ID + * + * @param int $id Row id of the record + * + * @return bool|array + * + * @see \Friendica\Database\DBA::select + */ + public static function getById($id) + { + return self::selectFirst([], ['id' => $id]); + } + + /** + * @brief Retrive a single record given the ID + * + * @param int $id Row id of the record + * + * @return bool|array + * + * @see \Friendica\Database\DBA::select + */ + public static function getByIdWithPermission($id) + { + $r = self::selectFirst(['uid'], ['id' => $id]); + if ($r === false) { + return false; + } + + $sql_acl = Security::getPermissionsSQLByUserId($r['uid']); + + $conditions = [ + '`id` = ?' . $sql_acl, + $id + ]; + + $item = self::selectFirst([], $conditions); + + return $item; + } + + /** + * @brief Get file data for given row id. null if row id does not exist + * + * @param array $item Attachment data. Needs at least 'id', 'backend-class', 'backend-ref' + * + * @return string file data + */ + public static function getData($item) + { + if ($item['backend-class'] == '') { + // legacy data storage in 'data' column + $i = self::selectFirst(['data'], ['id' => $item['id']]); + if ($i === false) { + return null; + } + return $i['data']; + } else { + $backendClass = $item['backend-class']; + $backendRef = $item['backend-ref']; + return $backendClass::get($backendRef); + } + } +} \ No newline at end of file diff --git a/src/Module/Attach.php b/src/Module/Attach.php new file mode 100644 index 0000000000..eed1275c58 --- /dev/null +++ b/src/Module/Attach.php @@ -0,0 +1,67 @@ +<?php +/** + * @file src/Module/Attach.php + */ + + +namespace Friendica\Module; + +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\System; +use Friendica\Core\Logger; +use Friendica\Model\Attach as MAttach; + +/** + * @brief Attach Module + */ +class Attach extends BaseModule +{ + /** + * @brief Module initializer + * + * Fetch an attached file given the id + */ + public static function init() + { + $a = self::getApp(); + if ($a->argc != 2) { + System::httpExit(400); // Bad Request. + } + + + $item_id = intval($a->argv[1]); + + // Check for existence + $item = MAttach::exists(['id' => $item_id]); + if ($item === false) { + System::httpExit(404, ['description' => L10n::t('Item was not found.')]); + } + + // Now we'll fetch the item, if we have enough permisson + $item = MAttach::getByIdWithPermission($item_id); + if ($item === false) { + System::httpExit(403, ['description' => L10n::t('Permission denied.')]); + } + + $data = MAttach::getData($item); + if (is_null($data)) { + Logger::log('NULL data for attachment with id ' . $item['id']); + System::httpExit(404, ['description' => L10n::t('Item was not found.')]); + } + + // Use quotes around the filename to prevent a "multiple Content-Disposition" + // error in Chrome for filenames with commas in them + header('Content-type: ' . $item['filetype']); + header('Content-length: ' . $item['filesize']); + if (isset($_GET['attachment']) && $_GET['attachment'] === '0') { + header('Content-disposition: filename="' . $item['filename'] . '"'); + } else { + header('Content-disposition: attachment; filename="' . $item['filename'] . '"'); + } + + echo $data; + exit(); + // NOTREACHED + } +} \ No newline at end of file -- 2.39.5