diff --git a/phpBB/config/default/container/services_storage.yml b/phpBB/config/default/container/services_storage.yml index 7216b4b5c4..4223bdb2bf 100644 --- a/phpBB/config/default/container/services_storage.yml +++ b/phpBB/config/default/container/services_storage.yml @@ -12,14 +12,17 @@ services: storage.avatar: class: phpbb\storage\storage arguments: + - '@dbal.conn' - '@storage.adapter.factory' - 'avatar' + - '%tables.storage%' tags: - { name: storage } storage.backup: class: phpbb\storage\storage arguments: + - '@dbal.conn' - '@storage.adapter.factory' - 'backup' tags: diff --git a/phpBB/config/default/container/tables.yml b/phpBB/config/default/container/tables.yml index 6adacca0d0..f3c2282de9 100644 --- a/phpBB/config/default/container/tables.yml +++ b/phpBB/config/default/container/tables.yml @@ -60,6 +60,7 @@ parameters: tables.sitelist: '%core.table_prefix%sitelist' tables.smilies: '%core.table_prefix%smilies' tables.sphinx: '%core.table_prefix%sphinx' + tables.storage: '%core.table_prefix%storage' tables.styles: '%core.table_prefix%styles' tables.styles_template: '%core.table_prefix%styles_template' tables.styles_template_data: '%core.table_prefix%styles_template_data' diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index ee8b642b9b..dcab741366 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -288,6 +288,7 @@ define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys'); define('SITELIST_TABLE', $table_prefix . 'sitelist'); define('SMILIES_TABLE', $table_prefix . 'smilies'); define('SPHINX_TABLE', $table_prefix . 'sphinx'); +define('STORAGE_TABLE', $table_prefix . 'storage'); define('STYLES_TABLE', $table_prefix . 'styles'); define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template'); define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data'); diff --git a/phpBB/phpbb/db/migration/data/v330/storage_track.php b/phpBB/phpbb/db/migration/data/v330/storage_track.php new file mode 100644 index 0000000000..455fa4e94f --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/storage_track.php @@ -0,0 +1,43 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v330; + +class storage_track extends \phpbb\db\migration\migration +{ + public function update_schema() + { + return array( + 'add_tables' => array( + $this->table_prefix . 'storage' => array( + 'COLUMNS' => array( + 'file_id' => array('UINT', null, 'auto_increment'), + 'file_path' => array('VCHAR', ''), + 'storage' => array('VCHAR', ''), + 'filesize' => array('UINT:20', 0), + ), + 'PRIMARY_KEY' => 'file_id', + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'drop_tables' => array( + $this->table_prefix . 'storage', + ), + ); + } +} diff --git a/phpBB/phpbb/storage/storage.php b/phpBB/phpbb/storage/storage.php index 862b039c6a..cab2b26b4e 100644 --- a/phpBB/phpbb/storage/storage.php +++ b/phpBB/phpbb/storage/storage.php @@ -13,16 +13,28 @@ namespace phpbb\storage; +use phpbb\db\driver\driver_interface; + /** * @internal Experimental */ class storage { + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + /** * @var string */ protected $storage_name; + /** + * @var string + */ + protected $storage_table; + /** * @var \phpbb\storage\adapter_factory */ @@ -36,13 +48,16 @@ class storage /** * Constructor * + * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\storage\adapter_factory $factory * @param string $storage_name */ - public function __construct(adapter_factory $factory, $storage_name) + public function __construct(driver_interface $db, adapter_factory $factory, $storage_name, $storage_table) { + $this->db = $db; $this->factory = $factory; $this->storage_name = $storage_name; + $this->storage_table = $storage_table; } /** @@ -81,7 +96,23 @@ class storage */ public function put_contents($path, $content) { - $this->get_adapter()->put_contents($path, $content); + try + { + $this->get_adapter()->put_contents($path, $content); + + $sql_ary = array( + 'file_path' => $path, + 'storage' => $this->get_name(), + 'filesize' => strlen($content), + ); + + $sql = 'INSERT INTO ' . $this->storage_table . $this->db->sql_build_array('INSERT', $sql_ary); + $this->db->sql_query($sql); + } + catch (\Exception $e) + { + throw $e; + } } /** @@ -121,7 +152,23 @@ class storage */ public function delete($path) { - $this->get_adapter()->delete($path); + try + { + $this->get_adapter()->delete($path); + + $sql_ary = array( + 'file_path' => $path, + 'storage' => $this->get_name(), + ); + + $sql = 'DELETE FROM ' . $this->storage_table . ' + WHERE ' . $this->db->sql_build_array('DELETE', $sql_ary); + $this->db->sql_query($sql); + } + catch (\Exception $e) + { + throw $e; + } } /** @@ -135,7 +182,28 @@ class storage */ public function rename($path_orig, $path_dest) { - $this->get_adapter()->rename($path_orig, $path_dest); + try + { + $this->get_adapter()->rename($path_orig, $path_dest); + + $sql_ary1 = array( + 'file_path' => $path_dest, + ); + + $sql_ary2 = array( + 'file_path' => $path_orig, + 'storage' => $this->get_name(), + ); + + $sql = 'UPDATE ' . $this->storage_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary1) . ' + WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary2); + $this->db->sql_query($sql); + } + catch (\Exception $e) + { + throw $e; + } } /** @@ -149,7 +217,34 @@ class storage */ public function copy($path_orig, $path_dest) { - $this->get_adapter()->copy($path_orig, $path_dest); + try + { + $this->get_adapter()->copy($path_orig, $path_dest); + + $sql_ary = array( + 'file_path' => $path_orig, + 'storage' => $this->get_name(), + ); + + $sql = 'SELECT filesize FROM ' . $this->storage_table . ' + WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $sql_ary = array( + 'file_path' => $path_dest, + 'storage' => $this->get_name(), + 'filesize' => (int) $row['filesize'], + ); + + $sql = 'INSERT INTO ' . $this->storage_table . $this->db->sql_build_array('INSERT', $sql_ary); + $this->db->sql_query($sql); + } + catch (\Exception $e) + { + throw $e; + } } /** @@ -158,7 +253,7 @@ class storage * @param string $path File to read * * @throws \phpbb\storage\exception\exception When unable to open file - + * * @return resource Returns a file pointer */ public function read_stream($path) @@ -186,7 +281,8 @@ class storage * * @param string $path The target file * @param resource $resource The resource - * When target file cannot be created + * + * @throws \phpbb\storage\exception\exception When target file cannot be created */ public function write_stream($path, $resource) { @@ -195,6 +291,33 @@ class storage if ($adapter instanceof stream_interface) { $adapter->write_stream($path, $resource); + + $sql_ary = array( + 'file_path' => $path, + 'storage' => $this->get_name(), + ); + + // Get file, if exist update filesize, if not add new record + $sql = 'SELECT * FROM ' . $this->storage_table . ' + WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + $sql = 'UPDATE ' . $this->storage_table . ' + SET filesize = filesize + ' . strlen($content) . ' + WHERE ' . $this->db->sql_build_array('SELECT', $sql_ary); + $this->db->sql_query($sql); + } + else + { + $sql_ary['filesize'] = strlen($content); + + $sql = 'INSERT INTO ' . $this->storage_table . $this->db->sql_build_array('INSERT', $sql_ary); + $this->db->sql_query($sql); + } } else { @@ -229,4 +352,23 @@ class storage { return $this->get_adapter()->get_link($path); } + + /** + * Get total storage size. + * + * @param string $path The file + * + * @return int Size in bytes + */ + public function get_size() + { + $sql = 'SELECT SUM(filesize) AS total + FROM ' . $this->storage_table . ' + WHERE storage = ' . $this->get_name(); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + return $row['total']; + } } diff --git a/tests/avatar/manager_test.php b/tests/avatar/manager_test.php index 2866a1673d..30ef42e835 100644 --- a/tests/avatar/manager_test.php +++ b/tests/avatar/manager_test.php @@ -38,11 +38,12 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case $filesystem = new \phpbb\filesystem\filesystem(); $adapter = new \phpbb\storage\adapter\local($filesystem, new \FastImageSize\FastImageSize(), new \phpbb\mimetype\guesser(array(new \phpbb\mimetype\extension_guesser)), $phpbb_root_path); $adapter->configure(['path' => 'images/avatars/upload']); + $db = $this->createMock('\phpbb\db\driver\driver_interface'); $adapter_factory_mock = $this->createMock('\phpbb\storage\adapter_factory'); $adapter_factory_mock->expects($this->any()) ->method('get') ->willReturn($adapter); - $storage = new \phpbb\storage\storage($adapter_factory_mock, ''); + $storage = new \phpbb\storage\storage($db, $adapter_factory_mock, '', ''); // Prepare dependencies for avatar manager and driver $this->config = new \phpbb\config\config(array());