18ce3bd73SGreg Roach<?php 28ce3bd73SGreg Roach 38ce3bd73SGreg Roach/** 48ce3bd73SGreg Roach * webtrees: online genealogy 5*d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 68ce3bd73SGreg Roach * This program is free software: you can redistribute it and/or modify 78ce3bd73SGreg Roach * it under the terms of the GNU General Public License as published by 88ce3bd73SGreg Roach * the Free Software Foundation, either version 3 of the License, or 98ce3bd73SGreg Roach * (at your option) any later version. 108ce3bd73SGreg Roach * This program is distributed in the hope that it will be useful, 118ce3bd73SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 128ce3bd73SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138ce3bd73SGreg Roach * GNU General Public License for more details. 148ce3bd73SGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 168ce3bd73SGreg Roach */ 178ce3bd73SGreg Roach 188ce3bd73SGreg Roachdeclare(strict_types=1); 198ce3bd73SGreg Roach 208ce3bd73SGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 218ce3bd73SGreg Roach 2281b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpNotFoundException; 238ce3bd73SGreg Roachuse Fisharebest\Webtrees\I18N; 248ce3bd73SGreg Roachuse Fisharebest\Webtrees\Media; 258ce3bd73SGreg Roachuse Fisharebest\Webtrees\Mime; 268ce3bd73SGreg Roachuse Fisharebest\Webtrees\Registry; 278ce3bd73SGreg Roachuse Fisharebest\Webtrees\Services\DatatablesService; 284991f205SGreg Roachuse Fisharebest\Webtrees\Services\LinkedRecordService; 298ce3bd73SGreg Roachuse Fisharebest\Webtrees\Services\MediaFileService; 308ce3bd73SGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 31748dbe15SGreg Roachuse Fisharebest\Webtrees\Validator; 328ce3bd73SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 338ce3bd73SGreg Roachuse Illuminate\Database\Query\Builder; 348ce3bd73SGreg Roachuse Illuminate\Database\Query\Expression; 358ce3bd73SGreg Roachuse Illuminate\Database\Query\JoinClause; 36f0448b68SGreg Roachuse League\Flysystem\FilesystemException; 37f7cf8a15SGreg Roachuse League\Flysystem\FilesystemOperator; 38f0448b68SGreg Roachuse League\Flysystem\UnableToCheckFileExistence; 39f32d77e6SGreg Roachuse League\Flysystem\UnableToReadFile; 40f7cf8a15SGreg Roachuse League\Flysystem\UnableToRetrieveMetadata; 418ce3bd73SGreg Roachuse Psr\Http\Message\ResponseInterface; 428ce3bd73SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 438ce3bd73SGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 448ce3bd73SGreg Roachuse Throwable; 458ce3bd73SGreg Roach 468ce3bd73SGreg Roachuse function assert; 478ce3bd73SGreg Roachuse function e; 48f7cf8a15SGreg Roachuse function getimagesizefromstring; 498ce3bd73SGreg Roachuse function intdiv; 508ce3bd73SGreg Roachuse function route; 518ce3bd73SGreg Roachuse function str_starts_with; 528ce3bd73SGreg Roachuse function strlen; 538ce3bd73SGreg Roachuse function substr; 548ce3bd73SGreg Roachuse function view; 558ce3bd73SGreg Roach 568ce3bd73SGreg Roach/** 578ce3bd73SGreg Roach * Manage media from the control panel. 588ce3bd73SGreg Roach */ 598ce3bd73SGreg Roachclass ManageMediaData implements RequestHandlerInterface 608ce3bd73SGreg Roach{ 61c4943cffSGreg Roach private DatatablesService $datatables_service; 628ce3bd73SGreg Roach 634991f205SGreg Roach private LinkedRecordService $linked_record_service; 644991f205SGreg Roach 65c4943cffSGreg Roach private MediaFileService $media_file_service; 668ce3bd73SGreg Roach 67c4943cffSGreg Roach private TreeService $tree_service; 688ce3bd73SGreg Roach 698ce3bd73SGreg Roach /** 708ce3bd73SGreg Roach * MediaController constructor. 718ce3bd73SGreg Roach * 728ce3bd73SGreg Roach * @param DatatablesService $datatables_service 734991f205SGreg Roach * @param LinkedRecordService $linked_record_service 748ce3bd73SGreg Roach * @param MediaFileService $media_file_service 758ce3bd73SGreg Roach * @param TreeService $tree_service 768ce3bd73SGreg Roach */ 778ce3bd73SGreg Roach public function __construct( 788ce3bd73SGreg Roach DatatablesService $datatables_service, 794991f205SGreg Roach LinkedRecordService $linked_record_service, 808ce3bd73SGreg Roach MediaFileService $media_file_service, 818ce3bd73SGreg Roach TreeService $tree_service 828ce3bd73SGreg Roach ) { 838ce3bd73SGreg Roach $this->datatables_service = $datatables_service; 844991f205SGreg Roach $this->linked_record_service = $linked_record_service; 858ce3bd73SGreg Roach $this->media_file_service = $media_file_service; 868ce3bd73SGreg Roach $this->tree_service = $tree_service; 878ce3bd73SGreg Roach } 888ce3bd73SGreg Roach 898ce3bd73SGreg Roach /** 908ce3bd73SGreg Roach * @param ServerRequestInterface $request 918ce3bd73SGreg Roach * 928ce3bd73SGreg Roach * @return ResponseInterface 938ce3bd73SGreg Roach */ 948ce3bd73SGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 958ce3bd73SGreg Roach { 968ce3bd73SGreg Roach $data_filesystem = Registry::filesystem()->data(); 978ce3bd73SGreg Roach 98748dbe15SGreg Roach $files = Validator::queryParams($request)->isInArray(['local', 'external', 'unused'])->string('files'); 998ce3bd73SGreg Roach 1008ce3bd73SGreg Roach // Files within this folder 101748dbe15SGreg Roach $media_folder = Validator::queryParams($request)->string('media_folder'); 1028ce3bd73SGreg Roach 1038ce3bd73SGreg Roach // Show sub-folders within $media_folder 104748dbe15SGreg Roach $subfolders = Validator::queryParams($request)->isInArray(['include', 'exclude'])->string('subfolders'); 1058ce3bd73SGreg Roach 1068ce3bd73SGreg Roach $search_columns = ['multimedia_file_refn', 'descriptive_title']; 1078ce3bd73SGreg Roach 1088ce3bd73SGreg Roach $sort_columns = [ 1098ce3bd73SGreg Roach 0 => 'multimedia_file_refn', 11096c9e653SGreg Roach 2 => new Expression('descriptive_title || multimedia_file_refn'), 1118ce3bd73SGreg Roach ]; 1128ce3bd73SGreg Roach 1138ce3bd73SGreg Roach // Convert a row from the database into a row for datatables 114f70bcff5SGreg Roach $callback = function (object $row): array { 1158ce3bd73SGreg Roach $tree = $this->tree_service->find((int) $row->m_file); 1168ce3bd73SGreg Roach $media = Registry::mediaFactory()->make($row->m_id, $tree, $row->m_gedcom); 1178ce3bd73SGreg Roach assert($media instanceof Media); 1188ce3bd73SGreg Roach 119f41d9852SGreg Roach $is_http = str_starts_with($row->multimedia_file_refn, 'http://'); 120f41d9852SGreg Roach $is_https = str_starts_with($row->multimedia_file_refn, 'https://'); 121f41d9852SGreg Roach 122f41d9852SGreg Roach if ($is_http || $is_https) { 1232fad1159SGreg Roach return [ 1242fad1159SGreg Roach '<a href="' . e($row->multimedia_file_refn) . '">' . e($row->multimedia_file_refn) . '</a>', 1252fad1159SGreg Roach view('icons/mime', ['type' => Mime::DEFAULT_TYPE]), 1262fad1159SGreg Roach $this->mediaObjectInfo($media), 1272fad1159SGreg Roach ]; 1282fad1159SGreg Roach } 1292fad1159SGreg Roach 130f41d9852SGreg Roach try { 1318ce3bd73SGreg Roach $path = $row->media_folder . $row->multimedia_file_refn; 1328ce3bd73SGreg Roach 1338ce3bd73SGreg Roach try { 134f7cf8a15SGreg Roach $mime_type = Registry::filesystem()->data()->mimeType($path); 13528d026adSGreg Roach } catch (UnableToRetrieveMetadata) { 136f7cf8a15SGreg Roach $mime_type = Mime::DEFAULT_TYPE; 137f7cf8a15SGreg Roach } 1388ce3bd73SGreg Roach 1398ce3bd73SGreg Roach if (str_starts_with($mime_type, 'image/')) { 1408ce3bd73SGreg Roach $url = route(AdminMediaFileThumbnail::class, ['path' => $path]); 1418ce3bd73SGreg Roach $img = '<img src="' . e($url) . '">'; 1428ce3bd73SGreg Roach } else { 1438ce3bd73SGreg Roach $img = view('icons/mime', ['type' => $mime_type]); 1448ce3bd73SGreg Roach } 1458ce3bd73SGreg Roach 1468ce3bd73SGreg Roach $url = route(AdminMediaFileDownload::class, ['path' => $path]); 1478ce3bd73SGreg Roach $img = '<a href="' . e($url) . '" type="' . $mime_type . '" class="gallery">' . $img . '</a>'; 14828d026adSGreg Roach } catch (UnableToReadFile) { 1498ce3bd73SGreg Roach $url = route(AdminMediaFileThumbnail::class, ['path' => $path]); 1508ce3bd73SGreg Roach $img = '<img src="' . e($url) . '">'; 1518ce3bd73SGreg Roach } 1528ce3bd73SGreg Roach 1538ce3bd73SGreg Roach return [ 1542fad1159SGreg Roach e($row->multimedia_file_refn), 1558ce3bd73SGreg Roach $img, 1568ce3bd73SGreg Roach $this->mediaObjectInfo($media), 1578ce3bd73SGreg Roach ]; 1588ce3bd73SGreg Roach }; 1598ce3bd73SGreg Roach 1608ce3bd73SGreg Roach switch ($files) { 1618ce3bd73SGreg Roach case 'local': 1628ce3bd73SGreg Roach $query = DB::table('media_file') 1638ce3bd73SGreg Roach ->join('media', static function (JoinClause $join): void { 1648ce3bd73SGreg Roach $join 1658ce3bd73SGreg Roach ->on('media.m_file', '=', 'media_file.m_file') 1668ce3bd73SGreg Roach ->on('media.m_id', '=', 'media_file.m_id'); 1678ce3bd73SGreg Roach }) 1689ba2a180SGreg Roach ->leftJoin('gedcom_setting', static function (JoinClause $join): void { 1699ba2a180SGreg Roach $join 1709ba2a180SGreg Roach ->on('gedcom_setting.gedcom_id', '=', 'media.m_file') 1719ba2a180SGreg Roach ->where('setting_name', '=', 'MEDIA_DIRECTORY'); 1729ba2a180SGreg Roach }) 1738ce3bd73SGreg Roach ->where('multimedia_file_refn', 'NOT LIKE', 'http://%') 1748ce3bd73SGreg Roach ->where('multimedia_file_refn', 'NOT LIKE', 'https://%') 1758ce3bd73SGreg Roach ->select([ 1768ce3bd73SGreg Roach 'media.*', 1778ce3bd73SGreg Roach 'multimedia_file_refn', 1788ce3bd73SGreg Roach 'descriptive_title', 1799ba2a180SGreg Roach new Expression("COALESCE(setting_value, 'media/') AS media_folder"), 1808ce3bd73SGreg Roach ]); 1818ce3bd73SGreg Roach 1828ce3bd73SGreg Roach $query->where(new Expression('setting_value || multimedia_file_refn'), 'LIKE', $media_folder . '%'); 1838ce3bd73SGreg Roach 1848ce3bd73SGreg Roach if ($subfolders === 'exclude') { 1858ce3bd73SGreg Roach $query->where(new Expression('setting_value || multimedia_file_refn'), 'NOT LIKE', $media_folder . '%/%'); 1868ce3bd73SGreg Roach } 1878ce3bd73SGreg Roach 1888ce3bd73SGreg Roach return $this->datatables_service->handleQuery($request, $query, $search_columns, $sort_columns, $callback); 1898ce3bd73SGreg Roach 1908ce3bd73SGreg Roach case 'external': 1918ce3bd73SGreg Roach $query = DB::table('media_file') 1928ce3bd73SGreg Roach ->join('media', static function (JoinClause $join): void { 1938ce3bd73SGreg Roach $join 1948ce3bd73SGreg Roach ->on('media.m_file', '=', 'media_file.m_file') 1958ce3bd73SGreg Roach ->on('media.m_id', '=', 'media_file.m_id'); 1968ce3bd73SGreg Roach }) 1978ce3bd73SGreg Roach ->where(static function (Builder $query): void { 1988ce3bd73SGreg Roach $query 1998ce3bd73SGreg Roach ->where('multimedia_file_refn', 'LIKE', 'http://%') 2008ce3bd73SGreg Roach ->orWhere('multimedia_file_refn', 'LIKE', 'https://%'); 2018ce3bd73SGreg Roach }) 2028ce3bd73SGreg Roach ->select([ 2038ce3bd73SGreg Roach 'media.*', 2048ce3bd73SGreg Roach 'multimedia_file_refn', 2058ce3bd73SGreg Roach 'descriptive_title', 20696c9e653SGreg Roach new Expression("'' AS media_folder"), 2078ce3bd73SGreg Roach ]); 2088ce3bd73SGreg Roach 2098ce3bd73SGreg Roach return $this->datatables_service->handleQuery($request, $query, $search_columns, $sort_columns, $callback); 2108ce3bd73SGreg Roach 2118ce3bd73SGreg Roach case 'unused': 2128ce3bd73SGreg Roach // Which trees use which media folder? 2138ce3bd73SGreg Roach $media_trees = DB::table('gedcom') 2148ce3bd73SGreg Roach ->join('gedcom_setting', 'gedcom_setting.gedcom_id', '=', 'gedcom.gedcom_id') 2158ce3bd73SGreg Roach ->where('setting_name', '=', 'MEDIA_DIRECTORY') 2168ce3bd73SGreg Roach ->where('gedcom.gedcom_id', '>', 0) 2178ce3bd73SGreg Roach ->pluck('setting_value', 'gedcom_name'); 2188ce3bd73SGreg Roach 2198ce3bd73SGreg Roach $disk_files = $this->media_file_service->allFilesOnDisk($data_filesystem, $media_folder, $subfolders === 'include'); 2208ce3bd73SGreg Roach $db_files = $this->media_file_service->allFilesInDatabase($media_folder, $subfolders === 'include'); 2218ce3bd73SGreg Roach 2228ce3bd73SGreg Roach // All unused files 2238ce3bd73SGreg Roach $unused_files = $disk_files->diff($db_files) 2248ce3bd73SGreg Roach ->map(static function (string $file): array { 2258ce3bd73SGreg Roach return (array) $file; 2268ce3bd73SGreg Roach }); 2278ce3bd73SGreg Roach 2288ce3bd73SGreg Roach $search_columns = [0]; 2298ce3bd73SGreg Roach $sort_columns = [0 => 0]; 2308ce3bd73SGreg Roach 2318ce3bd73SGreg Roach $callback = function (array $row) use ($data_filesystem, $media_trees): array { 232f7cf8a15SGreg Roach try { 233f0448b68SGreg Roach $mime_type = $data_filesystem->mimeType($row[0]) ?: Mime::DEFAULT_TYPE; 23428d026adSGreg Roach } catch (FilesystemException | UnableToRetrieveMetadata) { 235f7cf8a15SGreg Roach $mime_type = Mime::DEFAULT_TYPE; 236f7cf8a15SGreg Roach } 237f7cf8a15SGreg Roach 2388ce3bd73SGreg Roach 2398ce3bd73SGreg Roach if (str_starts_with($mime_type, 'image/')) { 2408ce3bd73SGreg Roach $url = route(AdminMediaFileThumbnail::class, ['path' => $row[0]]); 2418ce3bd73SGreg Roach $img = '<img src="' . e($url) . '">'; 2428ce3bd73SGreg Roach } else { 2438ce3bd73SGreg Roach $img = view('icons/mime', ['type' => $mime_type]); 2448ce3bd73SGreg Roach } 2458ce3bd73SGreg Roach 2468ce3bd73SGreg Roach $url = route(AdminMediaFileDownload::class, ['path' => $row[0]]); 2478ce3bd73SGreg Roach $img = '<a href="' . e($url) . '">' . $img . '</a>'; 2488ce3bd73SGreg Roach 2498ce3bd73SGreg Roach // Form to create new media object in each tree 2508ce3bd73SGreg Roach $create_form = ''; 2518ce3bd73SGreg Roach foreach ($media_trees as $media_tree => $media_directory) { 2528ce3bd73SGreg Roach if (str_starts_with($row[0], $media_directory)) { 2538ce3bd73SGreg Roach $tmp = substr($row[0], strlen($media_directory)); 2548ce3bd73SGreg Roach $create_form .= 255315eb316SGreg Roach '<p><a href="#" data-bs-toggle="modal" data-bs-backdrop="static" data-bs-target="#modal-create-media-from-file" data-file="' . e($tmp) . '" data-url="' . e(route(CreateMediaObjectFromFile::class, ['tree' => $media_tree])) . '" onclick="document.getElementById(\'modal-create-media-from-file-form\').action=this.dataset.url; document.getElementById(\'file\').value=this.dataset.file;">' . I18N::translate('Create') . '</a> — ' . e($media_tree) . '<p>'; 2568ce3bd73SGreg Roach } 2578ce3bd73SGreg Roach } 2588ce3bd73SGreg Roach 259d4786c66SGreg Roach $delete_link = '<p><a data-wt-confirm="' . I18N::translate('Are you sure you want to delete “%s”?', e($row[0])) . '" data-wt-post-url="' . e(route(DeletePath::class, [ 2608ce3bd73SGreg Roach 'path' => $row[0], 2618ce3bd73SGreg Roach ])) . '" href="#">' . I18N::translate('Delete') . '</a></p>'; 2628ce3bd73SGreg Roach 2638ce3bd73SGreg Roach return [ 2648ce3bd73SGreg Roach $this->mediaFileInfo($data_filesystem, $row[0]) . $delete_link, 2658ce3bd73SGreg Roach $img, 2668ce3bd73SGreg Roach $create_form, 2678ce3bd73SGreg Roach ]; 2688ce3bd73SGreg Roach }; 2698ce3bd73SGreg Roach 2708ce3bd73SGreg Roach return $this->datatables_service->handleCollection($request, $unused_files, $search_columns, $sort_columns, $callback); 2718ce3bd73SGreg Roach 2728ce3bd73SGreg Roach default: 2738ce3bd73SGreg Roach throw new HttpNotFoundException(); 2748ce3bd73SGreg Roach } 2758ce3bd73SGreg Roach } 2768ce3bd73SGreg Roach 2778ce3bd73SGreg Roach /** 2788ce3bd73SGreg Roach * Generate some useful information and links about a media object. 2798ce3bd73SGreg Roach * 2808ce3bd73SGreg Roach * @param Media $media 2818ce3bd73SGreg Roach * 2828ce3bd73SGreg Roach * @return string HTML 2838ce3bd73SGreg Roach */ 2848ce3bd73SGreg Roach private function mediaObjectInfo(Media $media): string 2858ce3bd73SGreg Roach { 286d72643a1SDavid Drury $element = Registry::elementFactory()->make('NOTE:CONC'); 287c88ea636SGreg Roach $html = '<a href="' . e($media->url()) . '" title="' . e($media->tree()->title()) . '">' . $media->fullName() . '</a>'; 288c88ea636SGreg Roach 289c88ea636SGreg Roach if ($this->tree_service->all()->count() > 1) { 290c88ea636SGreg Roach $html .= ' — ' . e($media->tree()->title()); 291c88ea636SGreg Roach } 292c88ea636SGreg Roach 293c88ea636SGreg Roach $html .= $element->value($media->getNote(), $media->tree()); 2948ce3bd73SGreg Roach 2958ce3bd73SGreg Roach $linked = []; 2964991f205SGreg Roach 2974991f205SGreg Roach foreach ($this->linked_record_service->linkedIndividuals($media) as $link) { 298c88ea636SGreg Roach $linked[] = view('icons/individual') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 2998ce3bd73SGreg Roach } 3004991f205SGreg Roach 3014991f205SGreg Roach foreach ($this->linked_record_service->linkedFamilies($media) as $link) { 302c88ea636SGreg Roach $linked[] = view('icons/family') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 3038ce3bd73SGreg Roach } 3044991f205SGreg Roach 3054991f205SGreg Roach foreach ($this->linked_record_service->linkedSources($media) as $link) { 306c88ea636SGreg Roach $linked[] = view('icons/source') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 3078ce3bd73SGreg Roach } 3084991f205SGreg Roach 3094991f205SGreg Roach foreach ($this->linked_record_service->linkedNotes($media) as $link) { 310c88ea636SGreg Roach $linked[] = view('icons/note') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 3118ce3bd73SGreg Roach } 3124991f205SGreg Roach 3134991f205SGreg Roach foreach ($this->linked_record_service->linkedRepositories($media) as $link) { 314c88ea636SGreg Roach $linked[] = view('icons/media') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 3158ce3bd73SGreg Roach } 3164991f205SGreg Roach 3174991f205SGreg Roach foreach ($this->linked_record_service->linkedMedia($media) as $link) { 318c88ea636SGreg Roach $linked[] = view('icons/location') . '<a href="' . e($link->url()) . '">' . $link->fullName() . '</a>'; 3198ce3bd73SGreg Roach } 320c88ea636SGreg Roach 3218ce3bd73SGreg Roach if ($linked !== []) { 322c88ea636SGreg Roach $html .= '<ul class="list-unstyled">'; 3238ce3bd73SGreg Roach foreach ($linked as $link) { 3248ce3bd73SGreg Roach $html .= '<li>' . $link . '</li>'; 3258ce3bd73SGreg Roach } 3268ce3bd73SGreg Roach $html .= '</ul>'; 3278ce3bd73SGreg Roach } else { 3288ce3bd73SGreg Roach $html .= '<div class="alert alert-danger">' . I18N::translate('There are no links to this media object.') . '</div>'; 3298ce3bd73SGreg Roach } 3308ce3bd73SGreg Roach 3318ce3bd73SGreg Roach return $html; 3328ce3bd73SGreg Roach } 3338ce3bd73SGreg Roach 3348ce3bd73SGreg Roach /** 3358ce3bd73SGreg Roach * Generate some useful information and links about a media file. 3368ce3bd73SGreg Roach * 337f7cf8a15SGreg Roach * @param FilesystemOperator $data_filesystem 3388ce3bd73SGreg Roach * @param string $file 3398ce3bd73SGreg Roach * 3408ce3bd73SGreg Roach * @return string 3418ce3bd73SGreg Roach */ 342f7cf8a15SGreg Roach private function mediaFileInfo(FilesystemOperator $data_filesystem, string $file): string 3438ce3bd73SGreg Roach { 3448ce3bd73SGreg Roach $html = '<dl>'; 3458ce3bd73SGreg Roach $html .= '<dt>' . I18N::translate('Filename') . '</dt>'; 3468ce3bd73SGreg Roach $html .= '<dd>' . e($file) . '</dd>'; 3478ce3bd73SGreg Roach 348f0448b68SGreg Roach try { 349f0448b68SGreg Roach $file_exists = $data_filesystem->fileExists($file); 35028d026adSGreg Roach } catch (FilesystemException | UnableToCheckFileExistence) { 351f0448b68SGreg Roach $file_exists = false; 352f0448b68SGreg Roach } 353f0448b68SGreg Roach 354f0448b68SGreg Roach if ($file_exists) { 355f0448b68SGreg Roach try { 356f7cf8a15SGreg Roach $size = $data_filesystem->fileSize($file); 35728d026adSGreg Roach } catch (FilesystemException | UnableToRetrieveMetadata) { 358f0448b68SGreg Roach $size = 0; 359f0448b68SGreg Roach } 3608ce3bd73SGreg Roach $size = intdiv($size + 1023, 1024); // Round up to next KB 3618ce3bd73SGreg Roach /* I18N: size of file in KB */ 3628ce3bd73SGreg Roach $size = I18N::translate('%s KB', I18N::number($size)); 3638ce3bd73SGreg Roach $html .= '<dt>' . I18N::translate('File size') . '</dt>'; 3648ce3bd73SGreg Roach $html .= '<dd>' . $size . '</dd>'; 3658ce3bd73SGreg Roach 3668ce3bd73SGreg Roach try { 3678ce3bd73SGreg Roach // This will work for local filesystems. For remote filesystems, we will 3688ce3bd73SGreg Roach // need to copy the file locally to work out the image size. 369f7cf8a15SGreg Roach $imgsize = getimagesizefromstring($data_filesystem->read($file)); 3708ce3bd73SGreg Roach $html .= '<dt>' . I18N::translate('Image dimensions') . '</dt>'; 3718ce3bd73SGreg Roach /* I18N: image dimensions, width × height */ 3728ce3bd73SGreg Roach $html .= '<dd>' . I18N::translate('%1$s × %2$s pixels', I18N::number($imgsize['0']), I18N::number($imgsize['1'])) . '</dd>'; 37328d026adSGreg Roach } catch (FilesystemException | UnableToReadFile | Throwable) { 3748ce3bd73SGreg Roach // Not an image, or not a valid image? 3758ce3bd73SGreg Roach } 3768ce3bd73SGreg Roach } 3778ce3bd73SGreg Roach 3788ce3bd73SGreg Roach $html .= '</dl>'; 3798ce3bd73SGreg Roach 3808ce3bd73SGreg Roach return $html; 3818ce3bd73SGreg Roach } 3828ce3bd73SGreg Roach} 383