diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 006582772a..05de3c05bc 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -735,7 +735,10 @@ $lang = array_merge($lang, array( 'STORAGE_CANNOT_DELETE' => 'Can not delete file or folder.', 'STORAGE_CANNOT_RENAME' => 'Can not rename file or folder.', 'STORAGE_CANNOT_COPY' => 'Can not copy file or folder.', + 'STORAGE_CANNOT_COPY_RESOURCE' => 'Can not copy resource.', 'STORAGE_CANNOT_CREATE_DIR' => 'Can not create directory.', + 'STORAGE_CANNOT_OPEN_FILE' => 'Can not open file.', + 'STORAGE_CANNOT_CREATE_FILE' => 'Can not create file.', 'TB' => 'TB', 'TERMS_USE' => 'Terms of use', diff --git a/phpBB/phpbb/files/filespec_storage.php b/phpBB/phpbb/files/filespec_storage.php index b4042ebf10..c39c47dc38 100644 --- a/phpBB/phpbb/files/filespec_storage.php +++ b/phpBB/phpbb/files/filespec_storage.php @@ -447,7 +447,9 @@ class filespec_storage try { - $storage->put_contents($this->destination_file, file_get_contents($this->filename)); + $fp = fopen($this->filename, 'rb'); + $storage->write_stream($this->destination_file, $fp); + fclose($fp); } catch (\phpbb\storage\exception\exception $e) { diff --git a/phpBB/phpbb/storage/adapter/adapter_interface.php b/phpBB/phpbb/storage/adapter/adapter_interface.php index 207f001fad..b2f6043741 100644 --- a/phpBB/phpbb/storage/adapter/adapter_interface.php +++ b/phpBB/phpbb/storage/adapter/adapter_interface.php @@ -28,8 +28,8 @@ interface adapter_interface * @param string path The file to be written to. * @param string content The data to write into the file. * - * @throws \phpbb\storage\exception\exception When the file already exists - * When the file cannot be written + * @throws \phpbb\storage\exception\exception When the file already exists + * When the file cannot be written */ public function put_contents($path, $content); @@ -38,8 +38,9 @@ interface adapter_interface * * @param string $path The file to read * - * @throws \phpbb\storage\exception\exception When the file dont exists - * When cannot read file contents + * @throws \phpbb\storage\exception\exception When the file dont exists + * When cannot read file contents + * * @return string Returns file contents * */ @@ -50,7 +51,7 @@ interface adapter_interface * * @param string $path file/directory to check * - * @return bool Returns true if all files/directories exist, false otherwise + * @return bool Returns true if the file/directory exist, false otherwise. */ public function exists($path); @@ -59,7 +60,7 @@ interface adapter_interface * * @param string $path file/directory to remove * - * @throws \phpbb\storage\exception\exception When removal fails. + * @throws \phpbb\storage\exception\exception When removal fails. */ public function delete($path); @@ -69,8 +70,8 @@ interface adapter_interface * @param string $path_orig The original file/direcotry * @param string $path_dest The target file/directory * - * @throws \phpbb\storage\exception\exception When target exists - * When file/directory cannot be renamed + * @throws \phpbb\storage\exception\exception When target exists + * When file/directory cannot be renamed */ public function rename($path_orig, $path_dest); @@ -80,8 +81,8 @@ interface adapter_interface * @param string $path_orig The original filename * @param string $path_dest The target filename * - * @throws \phpbb\storage\exception\exception When target exists - * When the file cannot be copied + * @throws \phpbb\storage\exception\exception When target exists + * When the file cannot be copied */ public function copy($path_orig, $path_dest); } diff --git a/phpBB/phpbb/storage/adapter/local.php b/phpBB/phpbb/storage/adapter/local.php index a8498d6d8c..de63d0f6a5 100644 --- a/phpBB/phpbb/storage/adapter/local.php +++ b/phpBB/phpbb/storage/adapter/local.php @@ -13,6 +13,7 @@ namespace phpbb\storage\adapter; +use phpbb\storage\stream_interface; use phpbb\storage\exception\exception; use phpbb\filesystem\exception\filesystem_exception; use phpbb\filesystem\filesystem; @@ -21,7 +22,7 @@ use phpbb\filesystem\helper as filesystem_helper; /** * @internal Experimental */ -class local implements adapter_interface +class local implements adapter_interface, stream_interface { /** * Filesystem component @@ -195,4 +196,43 @@ class local implements adapter_interface $this->create_dir($path); } } + + /** + * {@inheritdoc} + */ + public function read_stream($path) + { + $stream = @fopen($this->root_path . $path, 'rb'); + + if (!$stream) + { + throw new exception('STORAGE_CANNOT_OPEN_FILE', $path); + } + + return $stream; + } + + /** + * {@inheritdoc} + */ + public function write_stream($path, $resource) + { + if ($this->exists($path)) + { + throw new exception('STORAGE_FILE_EXISTS', $path); + } + + $stream = @fopen($this->root_path . $path, 'w+b'); + + if (!$stream) + { + throw new exception('STORAGE_CANNOT_CREATE_FILE', $path); + } + + if (stream_copy_to_stream($resource, $stream) === false) + { + fclose($stream); + throw new exception('STORAGE_CANNOT_COPY_RESOURCE'); + } + } } diff --git a/phpBB/phpbb/storage/exception/not_implemented.php b/phpBB/phpbb/storage/exception/not_implemented.php deleted file mode 100644 index df535048e5..0000000000 --- a/phpBB/phpbb/storage/exception/not_implemented.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @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\storage\exception; - -class not_implemented extends exception -{ - -} diff --git a/phpBB/phpbb/storage/storage.php b/phpBB/phpbb/storage/storage.php index 65a4f6eb72..a2eb89ecb3 100644 --- a/phpBB/phpbb/storage/storage.php +++ b/phpBB/phpbb/storage/storage.php @@ -66,8 +66,8 @@ class storage * @param string path The file to be written to. * @param string content The data to write into the file. * - * @throws \phpbb\storage\exception\exception When the file already exists - * When the file cannot be written + * @throws \phpbb\storage\exception\exception When the file already exists + * When the file cannot be written */ public function put_contents($path, $content) { @@ -79,8 +79,9 @@ class storage * * @param string $path The file to read * - * @throws \phpbb\storage\exception\exception When the file dont exists - * When cannot read file contents + * @throws \phpbb\storage\exception\exception When the file dont exists + * When cannot read file contents + * * @return string Returns file contents * */ @@ -94,7 +95,7 @@ class storage * * @param string $path file/directory to check * - * @return bool Returns true if all files/directories exist, false otherwise + * @return bool Returns true if the file/directory exist, false otherwise. */ public function exists($path) { @@ -106,7 +107,7 @@ class storage * * @param string $path file/directory to remove * - * @throws \phpbb\storage\exception\exception When removal fails. + * @throws \phpbb\storage\exception\exception When removal fails. */ public function delete($path) { @@ -119,8 +120,8 @@ class storage * @param string $path_orig The original file/direcotry * @param string $path_dest The target file/directory * - * @throws \phpbb\storage\exception\exception When target exists - * When file/directory cannot be renamed + * @throws \phpbb\storage\exception\exception When target exists + * When file/directory cannot be renamed */ public function rename($path_orig, $path_dest) { @@ -133,11 +134,62 @@ class storage * @param string $path_orig The original filename * @param string $path_dest The target filename * - * @throws \phpbb\storage\exception\exception When target exists - * When the file cannot be copied + * @throws \phpbb\storage\exception\exception When target exists + * When the file cannot be copied */ public function copy($path_orig, $path_dest) { $this->get_adapter()->copy($path_orig, $path_dest); } + + /** + * Reads a file as a stream. + * + * @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) + { + $stream = null; + $adapter = $this->get_adapter(); + + if ($adapter instanceof stream_interface) + { + $stream = $adapter->read_stream($path); + } + else + { + // Simulate the stream + $stream = fopen('php://temp', 'w+b'); + fwrite($stream, $adapter->get_contents($path)); + rewind($stream); + } + + return $stream; + } + + /** + * Writes a new file using a stream. + * + * @param string $path The target file + * @param resource $resource The resource + * When target file cannot be created + */ + public function write_stream($path, $resource) + { + $adapter = $this->get_adapter(); + + if ($adapter instanceof stream_interface) + { + $adapter->write_stream($path, $resource); + } + else + { + // Simulate the stream + $adapter->put_contents($path, stream_get_contents($resource)); + } + } } diff --git a/phpBB/phpbb/storage/stream_interface.php b/phpBB/phpbb/storage/stream_interface.php new file mode 100644 index 0000000000..0ba866777a --- /dev/null +++ b/phpBB/phpbb/storage/stream_interface.php @@ -0,0 +1,39 @@ + + * @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\storage; + +interface stream_interface +{ + /** + * Reads a file as a stream. + * + * @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); + + /** + * Writes a new file using a stream. + * + * @param string $path The target file + * @param resource $resource The resource + * + * @throws \phpbb\storage\exception\exception When target file exists + * When target file cannot be created + */ + public function write_stream($path, $resource); +} diff --git a/tests/storage/adapter/local_test.php b/tests/storage/adapter/local_test.php index a2725cd387..6d3ba10bca 100644 --- a/tests/storage/adapter/local_test.php +++ b/tests/storage/adapter/local_test.php @@ -103,4 +103,23 @@ unlink($this->path . 'file2.txt'); } + public function test_read_stream() + { + file_put_contents($this->path . 'file.txt', ''); + $stream = $this->adapter->read_stream('file.txt'); + $this->assertTrue(is_resource($stream)); + fclose($stream); + unlink($this->path . 'file.txt'); + } + + public function test_write_stream() + { + file_put_contents($this->path . 'file.txt', 'abc'); + $stream = fopen($this->path . 'file.txt', 'rb'); + $this->adapter->write_stream('file2.txt', $stream); + fclose($stream); + $this->assertEquals(file_get_contents($this->path . 'file2.txt'), 'abc'); + unlink($this->path . 'file.txt'); + unlink($this->path . 'file2.txt'); + } }