[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
05122024
/
htdocs
/
jurnal-kesmas
/
lib
/
pkp
/
classes
/
services
/
[
Home
]
File: PKPFileService.php
<?php /** * @file classes/services/PKPFileService.php * * Copyright (c) 2014-2021 Simon Fraser University * Copyright (c) 2000-2021 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. * * @class PKPFileService * * @ingroup services * * @brief Helper class that encapsulates business logic for publications */ namespace PKP\services; use APP\core\Application; use Exception; use finfo; use Illuminate\Support\Facades\DB; use League\Flysystem\Filesystem; use League\Flysystem\Local\LocalFilesystemAdapter; use League\Flysystem\UnixVisibility\PortableVisibilityConverter; use PKP\config\Config; use PKP\core\PKPString; use PKP\file\FileManager; use PKP\plugins\Hook; class PKPFileService { private const FALLBACK_MIME_TYPE = 'application/octet-stream'; /** @var Filesystem */ public $fs; /** * Initialize and configure flysystem */ public function __construct() { $umask = Config::getVar('files', 'umask', 0022); $adapter = new LocalFilesystemAdapter( Config::getVar('files', 'files_dir'), PortableVisibilityConverter::fromArray([ 'file' => [ 'public' => FileManager::FILE_MODE_MASK & ~$umask, 'private' => FileManager::FILE_MODE_MASK & ~$umask, ], 'dir' => [ 'public' => FileManager::DIRECTORY_MODE_MASK & ~$umask, 'private' => FileManager::DIRECTORY_MODE_MASK & ~$umask, ] ]), LOCK_EX, LocalFilesystemAdapter::DISALLOW_LINKS ); Hook::call('File::adapter', [&$adapter, $this]); $this->fs = new Filesystem($adapter); } /** * Get a file by its id * * @param int $id * * @return object */ public function get($id) { $file = DB::table('files') ->where('file_id', '=', $id) ->select(['file_id as id', 'path', 'mimetype']) ->first(); return $file; } /** * Add a file * * @param string $from absolute path to file * @param string $to relative path in file dir * * @return int file id */ public function add($from, $to) { $stream = fopen($from, 'r+'); if (!$stream) { throw new Exception("Unable to copy {$from} to {$to}."); } $this->fs->writeStream($to, $stream); if (is_resource($stream)) { fclose($stream); } try { $mimetype = $this->fs->mimeType($to); } catch (Exception $e) { // When a very good mime-type cannot be guessed, FlySystem emits an Exception $mimetype = (new finfo(FILEINFO_MIME_TYPE))->file($to) ?: static::FALLBACK_MIME_TYPE; } // Check and override ambiguous mime types based on file extension if ($extension = pathinfo($to, PATHINFO_EXTENSION)) { $checkAmbiguous = strtolower($extension . ':' . $mimetype); if (array_key_exists($checkAmbiguous, $extensionsMap = PKPString::getAmbiguousExtensionsMap())) { $mimetype = $extensionsMap[$checkAmbiguous]; } } return DB::table('files')->insertGetId([ 'path' => $to, 'mimetype' => $mimetype, ], 'file_id'); } /** * Delete an uploaded file * * @param int $id */ public function delete($id) { $file = $this->get($id); if (!$file) { throw new Exception("Unable to locate file {$id}."); } $path = $file->path; if ($this->fs->has($path)) { try { $this->fs->delete($path); } catch (Exception $e) { throw new Exception("Unable to delete file {$id} at {$path}."); } } DB::table('files') ->where('file_id', '=', $file->id) ->delete(); } /** * Download a file * * This method sends a HTTP response and ends the request handling. * No code will run after this method is called. * * @param int $fileId File ID * @param string $filename Filename to give to the downloaded file * @param bool $inline Whether to stream the file to the browser */ public function download($fileId, $filename, $inline = false) { $file = $this->get($fileId); $dispatcher = Application::get()->getRequest()->getDispatcher(); if (!$file) { $dispatcher->handle404(); } $path = $file->path; if (!$this->fs->has($path)) { $dispatcher->handle404(); } if (Hook::call('File::download', [$file, &$filename, $inline])) { return; } // Stream the file to the end user. $mimetype = $file->mimetype ?? 'application/octet-stream'; $filesize = $this->fs->fileSize($path); $encodedFilename = urlencode($filename); header("Content-Type: {$mimetype}"); header("Content-Length: {$filesize}"); header('Accept-Ranges: none'); header('Content-Disposition: ' . ($inline ? 'inline' : 'attachment') . ";filename=\"{$encodedFilename}\";filename*=UTF-8''{$encodedFilename}"); header('Cache-Control: private'); // Workarounds for IE weirdness header('Pragma: public'); fpassthru($this->fs->readStream($path)); exit; } /** * Convert a filename into a consistent format with the correct extension * * @param string $path Path to the file * @param string $filename Source filename to sanitize * * @return string */ public function formatFilename($path, $filename) { $newFilename = $filename; # pattern extended to also capture captures .tar.gz extensions if (preg_match('/(\\.\\w{1,3})?\\.\\w+$/', $path, $extension)) { # If $newFilename has no/not the correct extension: Append extension if (strcasecmp(substr($newFilename, (strlen($extension[0]) * -1)), $extension[0]) != 0) { $newFilename .= $extension[0]; } } Hook::call('File::formatFilename', [&$newFilename, $path, $filename]); return $newFilename; } /** * Get document type based on the mimetype * * @param string $mimetype * * @return string One of the FileManager::DOCUMENT_TYPE_ constants */ public function getDocumentType($mimetype) { switch ($mimetype) { case 'application/pdf': case 'application/x-pdf': case 'text/pdf': case 'text/x-pdf': return FileManager::DOCUMENT_TYPE_PDF; case 'application/msword': case 'application/word': case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': return FileManager::DOCUMENT_TYPE_WORD; case 'application/excel': case 'application/vnd.ms-excel': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': return FileManager::DOCUMENT_TYPE_EXCEL; case 'text/html': return FileManager::DOCUMENT_TYPE_HTML; case 'application/zip': case 'application/x-zip': case 'application/x-zip-compressed': case 'application/x-compress': case 'application/x-compressed': case 'multipart/x-zip': return FileManager::DOCUMENT_TYPE_ZIP; case 'application/epub': case 'application/epub+zip': return FileManager::DOCUMENT_TYPE_EPUB; case 'image/gif': case 'image/jpeg': case 'image/pjpeg': case 'image/png': case 'image/x-png': case 'image/vnd.microsoft.icon': case 'image/x-icon': case 'image/x-ico': case 'image/ico': return FileManager::DOCUMENT_TYPE_IMAGE; case 'application/x-shockwave-flash': case 'video/x-flv': case 'application/x-flash-video': case 'flv-application/octet-stream': case 'video/mpeg': case 'video/quicktime': case 'video/mp4': return FileManager::DOCUMENT_TYPE_VIDEO; case 'audio/mpeg': case 'audio/x-aiff': case 'audio/x-wav': return FileManager::DOCUMENT_TYPE_AUDIO; default: return FileManager::DOCUMENT_TYPE_DEFAULT; } } /** * Get a pretty file size string * * Examples: 82B, 12KB, 2MB, 2GB * * @param int $size File size in bytes * * @return string */ public function getNiceFileSize($size) { $niceFileSizeUnits = ['B', 'KB', 'MB', 'GB']; for ($i = 0; $i < 4 && $size > 1024; $i++) { $size >>= 10; } return $size . $niceFileSizeUnits[$i]; } }