From d058a70557ba26bcf81cce6f9a9e845cccfb73b3 Mon Sep 17 00:00:00 2001 From: Diogo Cordeiro Date: Sat, 19 Oct 2019 01:57:36 +0100 Subject: [PATCH] [MEDIA] Simplify Attachment actions --- actions/attachment.php | 136 ++++++++++++++++--------------- actions/attachment_download.php | 19 +---- actions/attachment_thumbnail.php | 65 ++++++--------- actions/attachment_view.php | 39 +++++---- classes/File.php | 6 +- lib/media/attachment.php | 23 ++++-- 6 files changed, 135 insertions(+), 153 deletions(-) diff --git a/actions/attachment.php b/actions/attachment.php index ae09a7256f..1c3d6a931a 100644 --- a/actions/attachment.php +++ b/actions/attachment.php @@ -1,33 +1,20 @@ . - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ +// This file is part of GNU social - https://www.gnu.org/software/social +// +// GNU social is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GNU social is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with GNU social. If not, see . -if (!defined('GNUSOCIAL')) { exit(1); } +defined('GNUSOCIAL') || die(); /** * Show notice attachments @@ -43,7 +30,13 @@ class AttachmentAction extends ManagedAction /** * Attachment File object to show */ - var $attachment = null; + public $attachment = null; + + public $filehash = null; + public $filepath = null; + public $filesize = null; + public $mimetype = null; + public $filename = null; /** * Load attributes based on database arguments @@ -52,41 +45,48 @@ class AttachmentAction extends ManagedAction * * @param array $args $_REQUEST array * - * @return success flag + * @return bool flag + * @throws ClientException + * @throws FileNotFoundException + * @throws FileNotStoredLocallyException + * @throws InvalidFilenameException + * @throws ServerException */ - - protected function prepare(array $args=array()) + protected function prepare(array $args = []) { parent::prepare($args); try { if (!empty($id = $this->trimmed('attachment'))) { $this->attachment = File::getByID($id); - } elseif (!empty($filehash = $this->trimmed('filehash'))) { - $this->attachment = File::getByHash($filehash); + } elseif (!empty($this->filehash = $this->trimmed('filehash'))) { + $this->attachment = File::getByHash($this->filehash); } } catch (Exception $e) { // Not found } if (!$this->attachment instanceof File) { // TRANS: Client error displayed trying to get a non-existing attachment. - $this->clientError(_('No such attachment.'), 404); + $this->clientError(_m('No such attachment.'), 404); } - $filename = $this->attachment->getFileOrThumbnailPath(); - - if (empty($filename)) { - $this->clientError(_('Requested local URL for a file that is not stored locally.'), 404); + $this->filepath = $this->attachment->getFileOrThumbnailPath(); + if (empty($this->filepath)) { + $this->clientError(_m('Requested local URL for a file that is not stored locally.'), 404); } + $this->filesize = $this->attachment->getFileOrThumbnailSize(); + $this->mimetype = $this->attachment->getFileOrThumbnailMimetype(); + $this->filename = MediaFile::getDisplayName($this->attachment); + return true; } /** * Is this action read-only? * - * @return boolean true + * @return bool true */ - function isReadOnly($args) + public function isReadOnly($args): bool { return true; } @@ -96,15 +96,15 @@ class AttachmentAction extends ManagedAction * * @return string title of the page */ - function title() + public function title(): string { $a = new Attachment($this->attachment); return $a->title(); } - public function showPage() + public function showPage(): void { - if (empty($this->attachment->getFileOrThumbnailPath())) { + if (empty($this->filepath)) { // if it's not a local file, gtfo common_redirect($this->attachment->getUrl(), 303); } @@ -119,10 +119,10 @@ class AttachmentAction extends ManagedAction * * @return void */ - function showContent() + public function showContent(): void { $ali = new Attachment($this->attachment, $this); - $cnt = $ali->show(); + $ali->show(); } /** @@ -130,7 +130,7 @@ class AttachmentAction extends ManagedAction * * @return void */ - function showPageNoticeBlock() + public function showPageNoticeBlock(): void { } @@ -139,7 +139,8 @@ class AttachmentAction extends ManagedAction * * @return void */ - function showSections() { + public function showSections(): void + { $ns = new AttachmentNoticeSection($this); $ns->show(); } @@ -148,13 +149,14 @@ class AttachmentAction extends ManagedAction * Last-modified date for file * * @return int last-modified date as unix timestamp + * @throws ServerException */ - public function lastModified() + public function lastModified(): ?int { if (common_config('site', 'use_x_sendfile')) { return null; } - $path = $this->attachment->getFileOrThumbnailPath(); + $path = $this->filepath; if (!empty($path)) { return filemtime($path); } else { @@ -169,26 +171,26 @@ class AttachmentAction extends ManagedAction * but in decimal instead of hex. * * @return string etag http header + * @throws ServerException */ - function etag() + public function etag(): string { if (common_config('site', 'use_x_sendfile')) { - return null; } - $path = $this->attachment->getFileOrThumbnailPath(); + $path = $this->filepath; $cache = Cache::instance(); - if($cache) { + if ($cache) { if (empty($path)) { return null; } $key = Cache::key('attachments:etag:' . $path); $etag = $cache->get($key); - if($etag === false) { + if ($etag === false) { $etag = crc32(file_get_contents($path)); - $cache->set($key,$etag); + $cache->set($key, $etag); } return $etag; } @@ -205,30 +207,30 @@ class AttachmentAction extends ManagedAction * Include $filepath in the response, for viewing and downloading. * If provided, $filesize is used to size the HTTP request, * otherwise it's value is calculated - * @param string $filepath the absolute path to the file to send - * @param $filesize optional, calculated if unkown + * @throws ServerException */ - static function sendFile(string $filepath, $filesize) { + public function sendFile(): void + { if (is_string(common_config('site', 'x-static-delivery'))) { - $tmp = explode(INSTALLDIR, $filepath); + $tmp = explode(INSTALLDIR, $this->filepath); $relative_path = end($tmp); common_debug("Using Static Delivery with header: '" . common_config('site', 'x-static-delivery') . ": {$relative_path}'"); header(common_config('site', 'x-static-delivery') . ": {$relative_path}"); } else { - if (empty($filesize)) { - $filesize = filesize($filepath); + if (empty($this->filesize)) { + $this->filesize = filesize($this->filepath); } - header("Content-Length: {$filesize}"); + header("Content-Length: {$this->filesize}"); // header('Cache-Control: private, no-transform, no-store, must-revalidate'); - $ret = @readfile($filepath); + $ret = @readfile($this->filepath); if ($ret === false) { - common_log(LOG_ERR, "Couldn't read file at {$filepath}."); - } elseif ($ret !== $filesize) { + common_log(LOG_ERR, "Couldn't read file at {$this->filepath}."); + } elseif ($ret !== $this->filesize) { common_log(LOG_ERR, "The lengths of the file as recorded on the DB (or on disk) for the file " . - "{$filepath} differ from what was sent to the user ({$filesize} vs {$ret})."); + "{$this->filepath} differ from what was sent to the user ({$this->filesize} vs {$ret})."); } } } diff --git a/actions/attachment_download.php b/actions/attachment_download.php index 62d5b43e47..e96e969a8d 100644 --- a/actions/attachment_download.php +++ b/actions/attachment_download.php @@ -13,30 +13,19 @@ if (!defined('GNUSOCIAL')) { exit(1); } */ class Attachment_downloadAction extends AttachmentAction { - public function showPage() + public function showPage(): void { - // Checks file exists or throws FileNotFoundException - $filepath = $this->attachment->getFileOrThumbnailPath(); - $filesize = $this->attachment->getFileOrThumbnailSize(); - $mimetype = $this->attachment->getFileOrThumbnailMimetype(); - - if (empty($filepath)) { - $this->clientError(_('No such attachment'), 404); - } - - $filename = MediaFile::getDisplayName($this->attachment); - // Disable errors, to not mess with the file contents (suppress errors in case access to this // function is blocked, like in some shared hosts). Automatically reset at the end of the // script execution, and we don't want to have any more errors until then, so don't reset it @ini_set('display_errors', 0); header("Content-Description: File Transfer"); - header("Content-Type: {$mimetype}"); - header("Content-Disposition: attachment; filename=\"{$filename}\""); + header("Content-Type: {$this->mimetype}"); + header("Content-Disposition: attachment; filename=\"{$this->filename}\""); header('Expires: 0'); header('Content-Transfer-Encoding: binary'); // FIXME? Can this be different? - AttachmentAction::sendFile($filepath, $filesize); + parent::sendFile(); } } diff --git a/actions/attachment_thumbnail.php b/actions/attachment_thumbnail.php index a4dad03f68..059ba2d04a 100644 --- a/actions/attachment_thumbnail.php +++ b/actions/attachment_thumbnail.php @@ -1,33 +1,20 @@ . - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ +// This file is part of GNU social - https://www.gnu.org/software/social +// +// GNU social is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GNU social is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with GNU social. If not, see . -if (!defined('GNUSOCIAL')) { exit(1); } +defined('GNUSOCIAL') || die(); /** * Show notice attachments @@ -58,10 +45,12 @@ class Attachment_thumbnailAction extends AttachmentAction * requested in the GET variables (read in the constructor). Tries * to send the most appropriate file with the correct size and * headers or displays an error if it's not possible. + * @throws ClientException + * @throws ReflectionException + * @throws ServerException */ - public function showPage() + public function showPage(): void { - // Returns a File_thumbnail object or throws exception if not available try { $thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c); @@ -69,27 +58,21 @@ class Attachment_thumbnailAction extends AttachmentAction } catch (UseFileAsThumbnailException $e) { // With this exception, the file exists locally $file = $e->file; - } catch(FileNotFoundException $e) { - $this->clientError(_('No such attachment'), 404); + } catch (FileNotFoundException $e) { + $this->clientError(_m('No such attachment'), 404); } - // Checks file exists or throws FileNotFoundException - $filepath = $file->getFileOrThumbnailPath($thumbnail); - $filesize = $this->attachment->getFileOrThumbnailSize($thumbnail); - $mimetype = $file->getFileOrThumbnailMimetype($thumbnail); - $filename = MediaFile::getDisplayName($file); - // Disable errors, to not mess with the file contents (suppress errors in case access to this // function is blocked, like in some shared hosts). Automatically reset at the end of the // script execution, and we don't want to have any more errors until then, so don't reset it @ini_set('display_errors', 0); header("Content-Description: File Transfer"); - header("Content-Type: {$mimetype}"); - header("Content-Disposition: inline; filename=\"{$filename}\""); + header("Content-Type: {$this->mimetype}"); + header("Content-Disposition: inline; filename=\"{$this->filename}\""); header('Expires: 0'); header('Content-Transfer-Encoding: binary'); - AttachmentAction::sendFile($filepath, $filesize); + parent::sendFile(); } } diff --git a/actions/attachment_view.php b/actions/attachment_view.php index cf33c6f6cf..01e35f74ef 100644 --- a/actions/attachment_view.php +++ b/actions/attachment_view.php @@ -1,6 +1,20 @@ . -if (!defined('GNUSOCIAL')) { exit(1); } +defined('GNUSOCIAL') || die(); /** * View notice attachment @@ -11,34 +25,23 @@ if (!defined('GNUSOCIAL')) { exit(1); } */ class Attachment_viewAction extends AttachmentAction { - public function showPage() + public function showPage(): void { - // Checks file exists or throws FileNotFoundException - $filepath = $this->attachment->getFileOrThumbnailPath(); - $filesize = $this->attachment->getFileOrThumbnailSize(); - $mimetype = $this->attachment->getFileOrThumbnailMimetype(); - - if (empty($filepath)) { - $this->clientError(_('No such attachment'), 404); - } - - $filename = MediaFile::getDisplayName($this->attachment); - // Disable errors, to not mess with the file contents (suppress errors in case access to this // function is blocked, like in some shared hosts). Automatically reset at the end of the // script execution, and we don't want to have any more errors until then, so don't reset it @ini_set('display_errors', 0); header("Content-Description: File Transfer"); - header("Content-Type: {$mimetype}"); - if (in_array(common_get_mime_media($mimetype), ['image', 'video'])) { - header("Content-Disposition: inline; filename=\"{$filename}\""); + header("Content-Type: {$this->mimetype}"); + if (in_array(common_get_mime_media($this->mimetype), ['image', 'video'])) { + header("Content-Disposition: inline; filename=\"{$this->filename}\""); } else { - header("Content-Disposition: attachment; filename=\"{$filename}\""); + header("Content-Disposition: attachment; filename=\"{$this->filename}\""); } header('Expires: 0'); header('Content-Transfer-Encoding: binary'); - AttachmentAction::sendFile($filepath, $filesize); + parent::sendFile(); } } diff --git a/classes/File.php b/classes/File.php index fe75a71ca7..e09d189be7 100644 --- a/classes/File.php +++ b/classes/File.php @@ -564,7 +564,7 @@ class File extends Managed_DataObject * @throws UnsupportedMediaException if, despite trying, we can't understand how to make a thumbnail for this format * @throws ServerException on various other errors */ - public function getThumbnail($width=null, $height=null, $crop=false, $force_still=true, $upscale=null): File_thumbnail + public function getThumbnail($width = null, $height = null, $crop = false, $force_still = true, $upscale = null): File_thumbnail { // Get some more information about this file through our ImageFile class $image = ImageFile::fromFileObject($this); @@ -610,7 +610,7 @@ class File extends Managed_DataObject * @throws InvalidFilenameException * @throws ServerException */ - public function getFileOrThumbnailPath(?File_thumbnail $thumbnail = null) : string + public function getFileOrThumbnailPath(?File_thumbnail $thumbnail = null): string { if (!empty($thumbnail)) { return $thumbnail->getPath(); @@ -803,7 +803,7 @@ class File extends Managed_DataObject public function noticeCount() { $cacheKey = sprintf('file:notice-count:%d', $this->id); - + $count = self::cacheGet($cacheKey); if ($count === false) { diff --git a/lib/media/attachment.php b/lib/media/attachment.php index 8e69b5a59a..265a3874c0 100644 --- a/lib/media/attachment.php +++ b/lib/media/attachment.php @@ -28,34 +28,39 @@ * @link http://status.net/ */ -if (!defined('GNUSOCIAL')) { exit(1); } +if (!defined('GNUSOCIAL')) { + exit(1); +} /** * used for one-off attachment action */ class Attachment extends AttachmentListItem { - function showNoticeAttachment() { - if (Event::handle('StartShowAttachmentLink', array($this->out, $this->attachment))) { - $this->out->elementStart('div', array('id' => 'attachment_view', - 'class' => 'h-entry')); + public function showNoticeAttachment() + { + if (Event::handle('StartShowAttachmentLink', [$this->out, $this->attachment])) { + $this->out->elementStart('div', ['id' => 'attachment_view', + 'class' => 'h-entry']); $this->out->elementStart('div', 'entry-title'); - $this->out->element('a', $this->linkAttr(), _('Download link')); + $this->out->element('a', $this->linkAttr(), _m('Download link')); $this->out->elementEnd('div'); $this->out->elementStart('article', 'e-content'); $this->showRepresentation(); $this->out->elementEnd('article'); - Event::handle('EndShowAttachmentLink', array($this->out, $this->attachment)); + Event::handle('EndShowAttachmentLink', [$this->out, $this->attachment]); $this->out->elementEnd('div'); } } - function show() { + public function show() + { $this->showNoticeAttachment(); } - function linkAttr() { + public function linkAttr() + { return array('rel' => 'external', 'href' => $this->attachment->getAttachmentDownloadUrl()); } }