diff --git a/plugins/Directory/Directory.php b/plugins/Directory/Directory.php index bf25408ebc..a700e0c42b 100644 --- a/plugins/Directory/Directory.php +++ b/plugins/Directory/Directory.php @@ -28,11 +28,7 @@ use App\Core\Router\RouteLoader; class Directory extends Module { /** - * Map URLs to actions - * - * @param RouteLoader $r - * - * @return bool hook value; true means continue processing, false means stop. + * Map URLs to Controllers */ public function onAddRoute(RouteLoader $r) { diff --git a/actions/attachment.php b/plugins/Media/Controller/Attachment.php similarity index 80% rename from actions/attachment.php rename to plugins/Media/Controller/Attachment.php index 5597a35100..3dae26da9c 100644 --- a/actions/attachment.php +++ b/plugins/Media/Controller/Attachment.php @@ -1,4 +1,6 @@ . +// }}} -defined('GNUSOCIAL') || die(); +namespace Plugin\Media\Controller; + +use App\Core\Controller; +use Symfony\Component\HttpFoundation\Request; /** - * Show notice attachments + * Show note attachments * - * @category Personal - * @package GNUsocial - * @author Evan Prodromou - * @copyright 2008-2009 StatusNet, Inc. - * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * @author Evan Prodromou + * @author Hugo Sales + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * + * @see http://status.net/ */ -class AttachmentAction extends ManagedAction +class Attachment extends Controller { + public function handle(Request $request) + { + return [ + '_template' => 'doc/tos.html.twig', + ]; + } + /** * Attachment File object to show */ - public $attachment = null; + public $attachment; - public $filehash = null; - public $filepath = null; - public $filesize = null; - public $mimetype = null; - public $filename = null; + public $filehash; + public $filepath; + public $filesize; + public $mimetype; + public $filename; /** * Load attributes based on database arguments @@ -45,16 +58,17 @@ class AttachmentAction extends ManagedAction * * @param array $args $_REQUEST array * - * @return bool flag * @throws ClientException * @throws FileNotFoundException * @throws FileNotStoredLocallyException * @throws InvalidFilenameException * @throws ServerException + * + * @return bool flag */ protected function prepare(array $args = []) { - parent::prepare($args); + // parent::prepare($args); try { if (!empty($id = $this->trimmed('attachment'))) { @@ -88,6 +102,8 @@ class AttachmentAction extends ManagedAction /** * Is this action read-only? * + * @param mixed $args + * * @return bool true */ public function isReadOnly($args): bool @@ -102,13 +118,18 @@ class AttachmentAction extends ManagedAction */ public function title(): string { - $a = new Attachment($this->attachment); + $a = new self($this->attachment); return $a->title(); } public function showPage(): void { - parent::showPage(); + if (empty($this->filepath)) { + // if it's not a local file, gtfo + common_redirect($this->attachment->getUrl(), 303); + } + + // parent::showPage(); } /** @@ -120,7 +141,7 @@ class AttachmentAction extends ManagedAction */ public function showContent(): void { - $ali = new Attachment($this->attachment, $this); + $ali = new self($this->attachment, $this); $ali->show(); } @@ -147,8 +168,9 @@ class AttachmentAction extends ManagedAction /** * Last-modified date for file * - * @return int last-modified date as unix timestamp * @throws ServerException + * + * @return int last-modified date as unix timestamp */ public function lastModified(): ?int { @@ -169,8 +191,9 @@ class AttachmentAction extends ManagedAction * This returns the same data (inode, size, mtime) as Apache would, * but in decimal instead of hex. * - * @return string etag http header * @throws ServerException + * + * @return string etag http header */ public function etag(): ?string { @@ -185,7 +208,7 @@ class AttachmentAction extends ManagedAction if (empty($path)) { return null; } - $key = Cache::key('attachments:etag:' . $path); + $key = Cache::key('attachments:etag:' . $path); $etag = $cache->get($key); if ($etag === false) { $etag = crc32(file_get_contents($path)); diff --git a/actions/attachment_download.php b/plugins/Media/Controller/AttachmentDownload.php similarity index 84% rename from actions/attachment_download.php rename to plugins/Media/Controller/AttachmentDownload.php index df0c4705aa..a993651c6a 100644 --- a/actions/attachment_download.php +++ b/plugins/Media/Controller/AttachmentDownload.php @@ -14,18 +14,20 @@ // You should have received a copy of the GNU Affero General Public License // along with GNU social. If not, see . -defined('GNUSOCIAL') || die(); +namespace Plugin\Media\Controller; /** * Download notice attachment * - * @category Personal - * @package GNUsocial - * @author Mikael Nordfeldth - * @copyright 2016 Free Software Foundation, Inc http://www.fsf.org - * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or late + * @category Personal + * @package GNUsocial + * + * @author Mikael Nordfeldth + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * + * @see https:/gnu.io/social */ -class Attachment_downloadAction extends AttachmentAction +class AttachmentDownload extends Attachment { public function showPage(): void { diff --git a/actions/attachment_thumbnail.php b/plugins/Media/Controller/AttachmentThumbnail.php similarity index 91% rename from actions/attachment_thumbnail.php rename to plugins/Media/Controller/AttachmentThumbnail.php index 05f4696695..da8d6857e6 100644 --- a/actions/attachment_thumbnail.php +++ b/plugins/Media/Controller/AttachmentThumbnail.php @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with GNU social. If not, see . -defined('GNUSOCIAL') || die(); +namespace Plugin\Media\Controller; /** * Show notice attachments @@ -27,9 +27,9 @@ defined('GNUSOCIAL') || die(); */ class Attachment_thumbnailAction extends Attachment_viewAction { - protected $thumb_w = null; // max width - protected $thumb_h = null; // max height - protected $thumb_c = null; // crop? + protected $thumb_w; // max width + protected $thumb_h; // max height + protected $thumb_c; // crop? protected function doPreparation() { @@ -45,6 +45,7 @@ class Attachment_thumbnailAction extends Attachment_viewAction * 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 @@ -56,8 +57,7 @@ class Attachment_thumbnailAction extends Attachment_viewAction $filepath = $this->filepath; try { $thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c); - $filename = $thumbnail->getFilename(); - $filepath = $thumbnail->getPath(); + $file = $thumbnail->getFile(); } catch (UseFileAsThumbnailException $e) { // With this exception, the file exists locally $e->file; } catch (FileNotFoundException $e) { diff --git a/actions/attachment_view.php b/plugins/Media/Controller/AttachmentView.php similarity index 86% rename from actions/attachment_view.php rename to plugins/Media/Controller/AttachmentView.php index d320e61f29..692b7dd3ed 100644 --- a/actions/attachment_view.php +++ b/plugins/Media/Controller/AttachmentView.php @@ -14,17 +14,17 @@ // You should have received a copy of the GNU Affero General Public License // along with GNU social. If not, see . -defined('GNUSOCIAL') || die(); +namespace Plugin\Media\Controller; /** * View notice attachment * - * @package GNUsocial - * @author Mikael Nordfeldth - * @copyright 2016 Free Software Foundation, Inc http://www.fsf.org - * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * @package GNUsocial + * + * @author Miguel Dantas + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 */ -class Attachment_viewAction extends AttachmentAction +class AttachmentView extends Attachment { public function showPage(): void { diff --git a/plugins/Media/Media.php b/plugins/Media/Media.php new file mode 100644 index 0000000000..f60ff9c5db --- /dev/null +++ b/plugins/Media/Media.php @@ -0,0 +1,48 @@ +. +// }}} + +namespace Plugin\Media; + +use App\Core\Event; +use App\Core\Module; +use App\Core\Router\RouteLoader; + +class Media extends Module +{ + /** + * Map URLs to Controllers + */ + public function onAddRoute(RouteLoader $r) + { + // foreach (['' => 'attachment', + // '/view' => 'attachment_view', + // '/download' => 'attachment_download', + // '/thumbnail' => 'attachment_thumbnail'] as $postfix => $action) { + // foreach (['filehash' => '[A-Za-z0-9._-]{64}', + // 'attachment' => '[0-9]+'] as $type => $match) { + // $r->connect($action, "attachment/:{$type}{$postfix}", + // ['action' => $action], + // [$type => $match]); + // } + // } + $r->connect('attachment', '/attachment/{filehash<[A-Za-z0-9._-]{64}>}', Controller\Attachment::class); + + return Event::next; + } +} diff --git a/lib/media/imagefile.php b/plugins/Media/Util/ImageFile.php similarity index 75% rename from lib/media/imagefile.php rename to plugins/Media/Util/ImageFile.php index 4b1d3f9821..c00e275f99 100644 --- a/lib/media/imagefile.php +++ b/plugins/Media/Util/ImageFile.php @@ -28,7 +28,8 @@ * @copyright 2008, 2019-2020 Free Software Foundation http://fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 */ -defined('GNUSOCIAL') || die(); + +namespace Plugin\Media\Util; use Intervention\Image\ImageManagerStatic as Image; @@ -55,93 +56,92 @@ class ImageFile extends MediaFile public $animated; // Animated image? (has more than 1 frame). null means untested public $mimetype; // The _ImageFile_ mimetype, _not_ the originating File object - /** - * ImageFile constructor. - * - * @param int|null $id The DB id of the file. Int if known, null if not. - * If null, it searches for it. If -1, it skips all DB - * interactions (useful for temporary objects) - * @param string $filepath The path of the file this media refers to. Required - * @param string|null $filehash The hash of the file, if known. Optional - * @param string|null $fileurl - * @throws ClientException - * @throws NoResultException - * @throws ServerException - * @throws UnsupportedMediaException - */ - public function __construct(?int $id = null, string $filepath, ?string $filehash = null, ?string $fileurl = null) - { - $old_limit = ini_set('memory_limit', common_config('attachments', 'memory_limit')); + // /** + // * ImageFile constructor. + // * + // * @param int|null $id The DB id of the file. Int if known, null if not. + // * If null, it searches for it. If -1, it skips all DB + // * interactions (useful for temporary objects) + // * @param string $filepath The path of the file this media refers to. Required + // * @param string|null $filehash The hash of the file, if known. Optional + // * + // * @throws ClientException + // * @throws NoResultException + // * @throws ServerException + // * @throws UnsupportedMediaException + // */ + // public function __construct(?int $id = null, string $filepath, ?string $filehash = null) + // { + // $old_limit = ini_set('memory_limit', common_config('attachments', 'memory_limit')); - // These do not have to be the same as fileRecord->filename for example, - // since we may have generated an image source file from something else! - $this->filepath = $filepath; - $this->filename = basename($filepath); + // // These do not have to be the same as fileRecord->filename for example, + // // since we may have generated an image source file from something else! + // $this->filepath = $filepath; + // $this->filename = basename($filepath); - $img = Image::make($this->filepath); - $this->mimetype = $img->mime(); + // $img = Image::make($this->filepath); + // $this->mimetype = $img->mime(); - $cmp = function ($obj, $type) { - if ($obj->mimetype == image_type_to_mime_type($type)) { - $obj->type = $type; - return true; - } - return false; - }; - if (!(($cmp($this, IMAGETYPE_GIF) && function_exists('imagecreatefromgif')) || - ($cmp($this, IMAGETYPE_JPEG) && function_exists('imagecreatefromjpeg')) || - ($cmp($this, IMAGETYPE_BMP) && function_exists('imagecreatefrombmp')) || - ($cmp($this, IMAGETYPE_WBMP) && function_exists('imagecreatefromwbmp')) || - ($cmp($this, IMAGETYPE_XBM) && function_exists('imagecreatefromxbm')) || - ($cmp($this, IMAGETYPE_PNG) && function_exists('imagecreatefrompng')) || - ($cmp($this, IMAGETYPE_WEBP) && function_exists('imagecreatefromwebp')) - ) - ) { - common_debug("Mimetype '{$this->mimetype}' was not recognized as a supported format"); - // TRANS: Exception thrown when trying to upload an unsupported image file format. - throw new UnsupportedMediaException(_m('Unsupported image format.'), $this->filepath); - } + // $cmp = function ($obj, $type) { + // if ($obj->mimetype == image_type_to_mime_type($type)) { + // $obj->type = $type; + // return true; + // } + // return false; + // }; + // if (!(($cmp($this, IMAGETYPE_GIF) && function_exists('imagecreatefromgif')) || + // ($cmp($this, IMAGETYPE_JPEG) && function_exists('imagecreatefromjpeg')) || + // ($cmp($this, IMAGETYPE_BMP) && function_exists('imagecreatefrombmp')) || + // ($cmp($this, IMAGETYPE_WBMP) && function_exists('imagecreatefromwbmp')) || + // ($cmp($this, IMAGETYPE_XBM) && function_exists('imagecreatefromxbm')) || + // ($cmp($this, IMAGETYPE_PNG) && function_exists('imagecreatefrompng')) || + // ($cmp($this, IMAGETYPE_WEBP) && function_exists('imagecreatefromwebp')) + // ) + // ) { + // common_debug("Mimetype '{$this->mimetype}' was not recognized as a supported format"); + // // TRANS: Exception thrown when trying to upload an unsupported image file format. + // throw new UnsupportedMediaException(_m('Unsupported image format.'), $this->filepath); + // } - $this->width = $img->width(); - $this->height = $img->height(); + // $this->width = $img->width(); + // $this->height = $img->height(); - parent::__construct( - $filepath, - $this->mimetype, - $filehash, - $id, - $fileurl - ); + // parent::__construct( + // $filepath, + // $this->mimetype, + // $filehash, + // $id + // ); - if ($this->type === IMAGETYPE_JPEG) { - // Orientation value to rotate thumbnails properly - $exif = @$img->exif(); - if (is_array($exif) && isset($exif['Orientation'])) { - switch ((int)($exif['Orientation'])) { - case 1: // top is top - $this->rotate = 0; - break; - case 3: // top is bottom - $this->rotate = 180; - break; - case 6: // top is right - $this->rotate = -90; - break; - case 8: // top is left - $this->rotate = 90; - break; - } - // If we ever write this back, Orientation should be set to '1' - } - } elseif ($this->type === IMAGETYPE_GIF) { - $this->animated = $this->isAnimatedGif(); - } + // if ($this->type === IMAGETYPE_JPEG) { + // // Orientation value to rotate thumbnails properly + // $exif = @$img->exif(); + // if (is_array($exif) && isset($exif['Orientation'])) { + // switch ((int)($exif['Orientation'])) { + // case 1: // top is top + // $this->rotate = 0; + // break; + // case 3: // top is bottom + // $this->rotate = 180; + // break; + // case 6: // top is right + // $this->rotate = -90; + // break; + // case 8: // top is left + // $this->rotate = 90; + // break; + // } + // // If we ever write this back, Orientation should be set to '1' + // } + // } elseif ($this->type === IMAGETYPE_GIF) { + // $this->animated = $this->isAnimatedGif(); + // } - Event::handle('FillImageFileMetadata', [$this]); + // Event::handle('FillImageFileMetadata', [$this]); - $img->destroy(); - ini_set('memory_limit', $old_limit); // Restore the old memory limit - } + // $img->destroy(); + // ini_set('memory_limit', $old_limit); // Restore the old memory limit + // } /** * Shortcut method to get an ImageFile from a File @@ -153,10 +153,24 @@ class ImageFile extends MediaFile * @throws NoResultException * @throws ServerException * @throws UnsupportedMediaException + * @throws UseFileAsThumbnailException + * + * @return ImageFile */ public static function fromFileObject(File $file) { - $media = common_get_mime_media($file->mimetype); + $imgPath = null; + $media = common_get_mime_media($file->mimetype); + if (Event::handle('CreateFileImageThumbnailSource', [$file, &$imgPath, $media])) { + if (empty($file->filename) && !file_exists($imgPath)) { + throw new FileNotFoundException($imgPath); + } + + // First some mimetype specific exceptions + switch ($file->mimetype) { + case 'image/svg+xml': + throw new UseFileAsThumbnailException($file); + } // And we'll only consider it an image if it has such a media type if ($media !== 'image') { @@ -183,17 +197,18 @@ class ImageFile extends MediaFile * Uses MediaFile's `fromUpload` to do the majority of the work * and ensures the uploaded file is in fact an image. * - * @param string $param + * @param string $param * @param null|Profile $scoped * - * @return ImageFile * @throws NoResultException * @throws NoUploadedMediaException * @throws ServerException * @throws UnsupportedMediaException * @throws UseFileAsThumbnailException - * * @throws ClientException + * + * @return ImageFile + * */ public static function fromUpload(string $param = 'upload', ?Profile $scoped = null): self { @@ -229,6 +244,8 @@ class ImageFile extends MediaFile * @throws ServerException * @throws UnsupportedMediaException * @throws UseFileAsThumbnailException + * + * @return ImageFile */ public static function fromUrl(string $url, ?Profile $scoped = null, ?string $name = null, ?int $file_id = null): self { @@ -270,13 +287,14 @@ class ImageFile extends MediaFile * * @param string $outpath * - * @return ImageFile the image stored at target path * @throws NoResultException * @throws ServerException * @throws UnsupportedMediaException * @throws UseFileAsThumbnailException - * * @throws ClientException + * + * @return ImageFile the image stored at target path + * */ public function copyTo($outpath) { @@ -287,22 +305,23 @@ class ImageFile extends MediaFile * Create and save a thumbnail image. * * @param string $outpath - * @param array $box width, height, boundary box (x,y,w,h) defaults to full image + * @param array $box width, height, boundary box (x,y,w,h) defaults to full image + * + * @throws UnsupportedMediaException + * @throws UseFileAsThumbnailException * * @return string full local filesystem filename * @return string full local filesystem filename - * @throws UnsupportedMediaException - * @throws UseFileAsThumbnailException * */ public function resizeTo($outpath, array $box = []) { - $box['width'] = isset($box['width']) ? (int)($box['width']) : $this->width; - $box['height'] = isset($box['height']) ? (int)($box['height']) : $this->height; - $box['x'] = isset($box['x']) ? (int)($box['x']) : 0; - $box['y'] = isset($box['y']) ? (int)($box['y']) : 0; - $box['w'] = isset($box['w']) ? (int)($box['w']) : $this->width; - $box['h'] = isset($box['h']) ? (int)($box['h']) : $this->height; + $box['width'] = isset($box['width']) ? (int) ($box['width']) : $this->width; + $box['height'] = isset($box['height']) ? (int) ($box['height']) : $this->height; + $box['x'] = isset($box['x']) ? (int) ($box['x']) : 0; + $box['y'] = isset($box['y']) ? (int) ($box['y']) : 0; + $box['w'] = isset($box['w']) ? (int) ($box['w']) : $this->width; + $box['h'] = isset($box['h']) ? (int) ($box['h']) : $this->height; if (!file_exists($this->filepath)) { // TRANS: Exception thrown during resize when image has been registered as present, @@ -321,20 +340,20 @@ class ImageFile extends MediaFile if (abs($this->rotate) == 90) { // Box is rotated 90 degrees in either direction, // so we have to redefine x to y and vice versa. - $tmp = $box['width']; - $box['width'] = $box['height']; + $tmp = $box['width']; + $box['width'] = $box['height']; $box['height'] = $tmp; - $tmp = $box['x']; - $box['x'] = $box['y']; - $box['y'] = $tmp; - $tmp = $box['w']; - $box['w'] = $box['h']; - $box['h'] = $tmp; + $tmp = $box['x']; + $box['x'] = $box['y']; + $box['y'] = $tmp; + $tmp = $box['w']; + $box['w'] = $box['h']; + $box['h'] = $tmp; } } $this->height = $box['h']; - $this->width = $box['w']; + $this->width = $box['w']; if (Event::handle('StartResizeImageFile', [$this, $outpath, $box])) { $outpath = $this->resizeToFile($outpath, $box); @@ -441,9 +460,10 @@ class ImageFile extends MediaFile * @param $crop int Crop to the size (not preserving aspect ratio) * @param int $rotate * - * @return array * @throws ServerException * + * @return array + * */ public static function getScalingValues( $width, @@ -467,8 +487,8 @@ class ImageFile extends MediaFile // Because GD doesn't understand EXIF orientation etc. if (abs($rotate) == 90) { - $tmp = $width; - $width = $height; + $tmp = $width; + $width = $height; $height = $tmp; } @@ -481,7 +501,7 @@ class ImageFile extends MediaFile if ($crop) { $s_ar = $width / $height; - $t_ar = $maxW / $maxH; + $t_ar = $maxW / $maxH; $rw = $maxW; $rh = $maxH; @@ -567,12 +587,12 @@ class ImageFile extends MediaFile // Throws FileNotFoundException or FileNotStoredLocallyException $this->filepath = $this->fileRecord->getFileOrThumbnailPath(); - $filename = basename($this->filepath); + $filename = basename($this->filepath); if ($width === null) { - $width = common_config('thumbnail', 'width'); + $width = common_config('thumbnail', 'width'); $height = common_config('thumbnail', 'height'); - $crop = common_config('thumbnail', 'crop'); + $crop = common_config('thumbnail', 'crop'); } if (!$upscale) { @@ -586,7 +606,7 @@ class ImageFile extends MediaFile if ($height === null) { $height = $width; - $crop = true; + $crop = true; } // Get proper aspect ratio width and height before lookup @@ -597,18 +617,18 @@ class ImageFile extends MediaFile $thumb = File_thumbnail::pkeyGet([ 'file_id' => $this->fileRecord->getID(), - 'width' => $width, - 'height' => $height, + 'width' => $width, + 'height' => $height, ]); if ($thumb instanceof File_thumbnail) { $this->height = $height; - $this->width = $width; + $this->width = $width; return $thumb; } $type = $this->preferredType(); - $ext = image_type_to_extension($type, true); + $ext = image_type_to_extension($type, true); // Decoding returns null if the file is in the old format $filename = MediaFile::decodeFilename(basename($this->filepath)); // Encoding null makes the file use 'untitled', and also replaces the extension @@ -617,8 +637,8 @@ class ImageFile extends MediaFile // The boundary box for our resizing $box = [ 'width' => $width, 'height' => $height, - 'x' => $x, 'y' => $y, - 'w' => $w, 'h' => $h, + 'x' => $x, 'y' => $y, + 'w' => $w, 'h' => $h, ]; $outpath = File_thumbnail::path( @@ -643,7 +663,7 @@ class ImageFile extends MediaFile )); $this->height = $box['height']; - $this->width = $box['width']; + $this->width = $box['width']; // Perform resize and store into file $outpath = $this->resizeTo($outpath, $box); diff --git a/lib/media/mediafile.php b/plugins/Media/Util/MediaFile.php similarity index 92% rename from lib/media/mediafile.php rename to plugins/Media/Util/MediaFile.php index 0a653fa6d3..e5a1c576b4 100644 --- a/lib/media/mediafile.php +++ b/plugins/Media/Util/MediaFile.php @@ -28,9 +28,8 @@ * @copyright 2008-2009, 2019-2021 Free Software Foundation http://fsf.org * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 */ -defined('GNUSOCIAL') || die(); -require_once INSTALLDIR . '/lib/util/tempfile.php'; +namespace Plugin\Media\Util; /** * Class responsible for abstracting media files @@ -45,46 +44,52 @@ class MediaFile public $short_fileurl; public $mimetype; - /** - * MediaFile constructor. - * - * @param string|null $filepath The path of the file this media refers to. Required - * @param string $mimetype The mimetype of the file. Required - * @param string|null $filehash The hash of the file, if known. Optional - * @param int|null $id The DB id of the file. Int if known, null if not. - * If null, it searches for it. If -1, it skips all DB - * interactions (useful for temporary objects) - * @param string|null $fileurl Provide if remote - * @throws ClientException - * @throws NoResultException - * @throws ServerException - */ - public function __construct(?string $filepath = null, string $mimetype, ?string $filehash = null, ?int $id = null, ?string $fileurl = null) - { - $this->filepath = $filepath; - $this->filename = basename($this->filepath); - $this->mimetype = $mimetype; - $this->filehash = is_null($filepath) ? null : self::getHashOfFile($this->filepath, $filehash); - $this->id = $id; - $this->fileurl = $fileurl; + // /** + // * MediaFile constructor. + // * + // * @param string $filepath The path of the file this media refers to. Required + // * @param string $mimetype The mimetype of the file. Required + // * @param string|null $filehash The hash of the file, if known. Optional + // * @param int|null $id The DB id of the file. Int if known, null if not. + // * If null, it searches for it. If -1, it skips all DB + // * interactions (useful for temporary objects) + // * + // * @throws ClientException + // * @throws NoResultException + // * @throws ServerException + // */ + // public function __construct(string $filepath, string $mimetype, ?string $filehash = null, ?int $id = null) + // { + // $this->filepath = $filepath; + // $this->filename = basename($this->filepath); + // $this->mimetype = $mimetype; + // $this->filehash = self::getHashOfFile($this->filepath, $filehash); + // $this->id = $id; - // If id is -1, it means we're dealing with a temporary object and don't want to store it in the DB, - // or add redirects - if ($this->id !== -1) { - if (!empty($this->id)) { - // If we have an id, load it - $this->fileRecord = new File(); - $this->fileRecord->id = $this->id; - if (!$this->fileRecord->find(true)) { - // If we have set an ID, we need that ID to exist! - throw new NoResultException($this->fileRecord); - } - } else { - // Otherwise, store it - $this->fileRecord = $this->storeFile(); - } - } - } + // // If id is -1, it means we're dealing with a temporary object and don't want to store it in the DB, + // // or add redirects + // if ($this->id !== -1) { + // if (!empty($this->id)) { + // // If we have an id, load it + // $this->fileRecord = new File(); + // $this->fileRecord->id = $this->id; + // if (!$this->fileRecord->find(true)) { + // // If we have set an ID, we need that ID to exist! + // throw new NoResultException($this->fileRecord); + // } + // } else { + // // Otherwise, store it + // $this->fileRecord = $this->storeFile(); + // } + + // $this->fileurl = common_local_url( + // 'attachment', + // ['attachment' => $this->fileRecord->id] + // ); + + // $this->short_fileurl = common_shorten_url($this->fileurl); + // } + // } /** * Shortcut method to get a MediaFile from a File @@ -177,12 +182,13 @@ class MediaFile * * This won't work for files >2GiB because PHP uses only 32bit. * - * @param string $filepath + * @param string $filepath * @param null|string $filehash * - * @return string * @throws ServerException * + * @return string + * */ public static function getHashOfFile(string $filepath, $filehash = null) { @@ -201,10 +207,11 @@ class MediaFile /** * Retrieve or insert as a file in the DB * - * @return object File * @throws ServerException - * * @throws ClientException + * + * @return object File + * */ protected function storeFile() { @@ -224,11 +231,11 @@ class MediaFile $file->url = $this->fileurl; $file->urlhash = is_null($file->url) ? null : File::hashurl($file->url); $file->filehash = $this->filehash; - $file->size = filesize($this->filepath); + $file->size = filesize($this->filepath); if ($file->size === false) { throw new ServerException('Could not read file to get its size'); } - $file->date = time(); + $file->date = time(); $file->mimetype = $this->mimetype; $file_id = $file->insert(); @@ -297,13 +304,14 @@ class MediaFile * Encodes a file name and a file hash in the new file format, which is used to avoid * having an extension in the file, removing trust in extensions, while keeping the original name * - * @param null|string $original_name - * @param string $filehash - * @param null|string|bool $ext from File::getSafeExtension + * @param null|string $original_name + * @param string $filehash + * @param null|bool|string $ext from File::getSafeExtension * - * @return string * @throws ClientException * @throws ServerException + * + * @return string */ public static function encodeFilename($original_name, string $filehash, $ext = null): string { @@ -322,7 +330,7 @@ class MediaFile if (!empty($ext)) { // Remove dots if we have them (make sure they're not repeated) - $ext = preg_replace('/^\.+/', '', $ext); + $ext = preg_replace('/^\.+/', '', $ext); $original_name = preg_replace('/\.+.+$/i', ".{$ext}", $original_name); } @@ -386,9 +394,9 @@ class MediaFile * This format should be respected. Notice the dash, which is important to distinguish it from the previous * format ("{$hash}.{$ext}") * - * @param string $param Form name - * @param Profile|null $scoped - * @return ImageFile|MediaFile + * @param string $param Form name + * @param null|Profile $scoped + * * @throws ClientException * @throws InvalidFilenameException * @throws NoResultException @@ -396,6 +404,8 @@ class MediaFile * @throws ServerException * @throws UnsupportedMediaException * @throws UseFileAsThumbnailException + * + * @return ImageFile|MediaFile */ public static function fromUpload(string $param = 'media', ?Profile $scoped = null) { @@ -478,7 +488,7 @@ class MediaFile } $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'], $_FILES[$param]['name']); - $media = common_get_mime_media($mimetype); + $media = common_get_mime_media($mimetype); $basename = basename($_FILES[$param]['name']); @@ -488,7 +498,7 @@ class MediaFile // Validate the image by re-encoding it. Additionally normalizes old formats to WebP, // keeping GIF untouched if animated $outpath = $img->resizeTo($img->filepath); - $ext = image_type_to_extension($img->preferredType(), false); + $ext = image_type_to_extension($img->preferredType(), false); } $filename = self::encodeFilename($basename, $filehash, isset($ext) ? $ext : File::getSafeExtension($basename)); @@ -532,6 +542,8 @@ class MediaFile * @throws ServerException * @throws UnsupportedMediaException * @throws UseFileAsThumbnailException + * + * @return ImageFile|MediaFile */ public static function fromUrl(string $url, ?Profile $scoped = null, ?string $name = null, ?int $file_id = null) { @@ -622,7 +634,7 @@ class MediaFile // Additionally normalises old formats to PNG, // keeping JPEG and GIF untouched. $outpath = $img->resizeTo($img->filepath); - $ext = image_type_to_extension($img->preferredType(), false); + $ext = image_type_to_extension($img->preferredType(), false); } $filename = self::encodeFilename( $basename, @@ -655,6 +667,9 @@ class MediaFile return new self($filepath, $mimetype, $filehash, $file_id, $url); } + /** + * Construct media fiile from an upload + */ public static function fromFileInfo(SplFileInfo $finfo, Profile $scoped = null) { $filehash = hash_file(File::FILEHASH_ALG, $finfo->getRealPath()); @@ -712,16 +727,17 @@ class MediaFile /** * Attempt to identify the content type of a given file. * - * @param string $filepath filesystem path as string (file must exist) - * @param bool $originalFilename (optional) for extension-based detection + * @param string $filepath filesystem path as string (file must exist) + * @param bool $originalFilename (optional) for extension-based detection + * + * @throws ServerException + * @throws ClientException if type is known, but not supported for local uploads * * @return string * * @fixme this seems to tie a front-end error message in, kinda confusing * - * @throws ServerException * - * @throws ClientException if type is known, but not supported for local uploads */ public static function getUploadedMimeType(string $filepath, $originalFilename = false) { @@ -821,7 +837,7 @@ class MediaFile 'text/plain', 'text/html', // Ironically, Wikimedia Commons' SVG_logo.svg is identified as text/html // TODO: for XML we could do better content-based sniffing too - 'text/xml',]; + 'text/xml', ]; $supported = common_config('attachments', 'supported'); diff --git a/lib/media/attachment.php b/plugins/Media/media/Attachment.php similarity index 92% rename from lib/media/attachment.php rename to plugins/Media/media/Attachment.php index 08b489a8d5..b0196bf002 100644 --- a/lib/media/attachment.php +++ b/plugins/Media/media/Attachment.php @@ -21,16 +21,16 @@ * * @category UI * @package StatusNet + * * @author Evan Prodromou * @author Sarven Capadisli * @copyright 2008 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/ + * + * @see http://status.net/ */ -if (!defined('GNUSOCIAL')) { - exit(1); -} +namespace Plugin\Media\media; /** * used for one-off attachment action @@ -41,7 +41,7 @@ class Attachment extends AttachmentListItem { if (Event::handle('StartShowAttachmentLink', [$this->out, $this->attachment])) { $this->out->elementStart('div', ['id' => 'attachment_view', - 'class' => 'h-entry']); + 'class' => 'h-entry', ]); $this->out->elementStart('div', 'entry-title'); $this->out->element('a', $this->linkAttr(), _m('Download link')); $this->out->elementEnd('div'); @@ -61,6 +61,6 @@ class Attachment extends AttachmentListItem public function linkAttr() { - return ['rel' => 'external', 'href' => $this->attachment->getUrl(null)]; + return ['rel' => 'external', 'href' => $this->attachment->getAttachmentDownloadUrl()]; } } diff --git a/lib/media/attachmentlist.php b/plugins/Media/media/AttachmentList.php similarity index 73% rename from lib/media/attachmentlist.php rename to plugins/Media/media/AttachmentList.php index 14697023cb..806122b3bd 100644 --- a/lib/media/attachmentlist.php +++ b/plugins/Media/media/AttachmentList.php @@ -21,14 +21,16 @@ * * @category UI * @package StatusNet + * * @author Evan Prodromou * @author Sarven Capadisli * @copyright 2008 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/ + * + * @see http://status.net/ */ -if (!defined('GNUSOCIAL')) { exit(1); } +namespace Plugin\Media\media; /** * widget for displaying a list of notice attachments @@ -40,29 +42,30 @@ if (!defined('GNUSOCIAL')) { exit(1); } * * @category UI * @package StatusNet + * * @author Evan Prodromou * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ + * + * @see http://status.net/ * @see Notice * @see NoticeListItem * @see ProfileNoticeList */ -class AttachmentList extends Widget +class AttachmentList { /** the current stream of notices being displayed. */ + public $notice; - var $notice = null; - - /** - * constructor - * - * @param Notice $notice stream of notices from DB_DataObject - */ - function __construct(Notice $notice, $out=null) - { - parent::__construct($out); - $this->notice = $notice; - } + // /** + // * constructor + // * + // * @param Notice $notice stream of notices from DB_DataObject + // */ + // function __construct(Notice $notice, $out=null) + // { + // // parent::__construct($out); + // $this->notice = $notice; + // } /** * show the list of attachments @@ -72,16 +75,22 @@ class AttachmentList extends Widget * * @return int count of items listed. */ - function show() + public function show() { - $attachments = $this->notice->attachments(); + $attachments = $this->notice->attachments(); + foreach ($attachments as $key => $att) { + // Remove attachments which are not representable with neither a title nor thumbnail + if ($att->getTitle() === _('Untitled attachment') && !$att->hasThumbnail()) { + unset($attachments[$key]); + } + } if (!count($attachments)) { return 0; } if ($this->notice->getProfile()->isSilenced()) { // TRANS: Message for inline attachments list in notices when the author has been silenced. - $this->element('div', ['class'=>'error'], + $this->element('div', ['class' => 'error'], _('Attachments are hidden because this profile has been silenced.')); return 0; } @@ -98,12 +107,12 @@ class AttachmentList extends Widget return count($attachments); } - function showListStart() + public function showListStart() { - $this->out->elementStart('ol', array('class' => 'attachments')); + $this->out->elementStart('ol', ['class' => 'attachments']); } - function showListEnd() + public function showListEnd() { $this->out->elementEnd('ol'); } @@ -115,7 +124,7 @@ class AttachmentList extends Widget * * @return AttachmentListItem a list item for displaying the attachment */ - function newListItem(File $attachment) + public function newListItem(File $attachment) { return new AttachmentListItem($attachment, $this->out); } diff --git a/lib/media/attachmentlistitem.php b/plugins/Media/media/AttachmentListItem.php similarity index 91% rename from lib/media/attachmentlistitem.php rename to plugins/Media/media/AttachmentListItem.php index ef33e6b20b..b75e1a6607 100644 --- a/lib/media/attachmentlistitem.php +++ b/plugins/Media/media/AttachmentListItem.php @@ -21,14 +21,16 @@ * * @category UI * @package StatusNet + * * @author Evan Prodromou * @author Sarven Capadisli * @copyright 2008 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/ + * + * @see http://status.net/ */ -if (!defined('GNUSOCIAL')) { exit(1); } +namespace Plugin\Media\media; /** * widget for displaying a single notice @@ -41,32 +43,35 @@ if (!defined('GNUSOCIAL')) { exit(1); } * * @category UI * @package StatusNet + * * @author Evan Prodromou * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ + * + * @see http://status.net/ * @see NoticeList * @see ProfileNoticeListItem */ -class AttachmentListItem extends Widget +class AttachmentListItem { /** The attachment this item will show. */ - - var $attachment = null; + public $attachment; /** * @param File $attachment the attachment we will display */ - function __construct(File $attachment, $out=null) - { - parent::__construct($out); - $this->attachment = $attachment; - } + // function __construct(File $attachment, $out=null) + // { + // // parent::__construct($out); + // $this->attachment = $attachment; + // } - function title() { + public function title() + { return $this->attachment->getTitle() ?: MediaFile::getDisplayName($this->attachment); } - function linkTitle() { + public function linkTitle() + { return $this->title(); } @@ -78,13 +83,13 @@ class AttachmentListItem extends Widget * * @return void */ - function show() + public function show() { $this->showStart(); try { $this->showNoticeAttachment(); } catch (Exception $e) { - $this->element('div', ['class'=>'error'], $e->getMessage()); + $this->element('div', ['class' => 'error'], $e->getMessage()); common_debug($e->getMessage()); } $this->showEnd(); @@ -98,17 +103,19 @@ class AttachmentListItem extends Widget ]; } - function showNoticeAttachment() + public function showNoticeAttachment() { $this->showRepresentation(); } - function showRepresentation() + /** + * Show in HTML + */ + public function showRepresentation() { $enclosure = $this->attachment->getEnclosure(); if (Event::handle('StartShowAttachmentRepresentation', [$this->out, $this->attachment])) { - $this->out->elementStart('label'); $this->out->element('a', ['rel' => 'external', 'href' => $this->attachment->getAttachmentUrl()], $this->title()); $this->out->elementEnd('label'); @@ -208,7 +215,7 @@ class AttachmentListItem extends Widget } } } - Event::handle('EndShowAttachmentRepresentation', array($this->out, $this->attachment)); + Event::handle('EndShowAttachmentRepresentation', [$this->out, $this->attachment]); } protected function showHtmlFile(File $attachment) @@ -225,19 +232,19 @@ class AttachmentListItem extends Widget protected function scrubHtmlFile(File $attachment) { $path = $attachment->getPath(); - $raw = file_get_contents($path); + $raw = file_get_contents($path); // Normalize... $dom = new DOMDocument(); - if(!$dom->loadHTML($raw)) { - common_log(LOG_ERR, "Bad HTML in local HTML attachment $path"); + if (!$dom->loadHTML($raw)) { + common_log(LOG_ERR, "Bad HTML in local HTML attachment {$path}"); return false; } // Remove