Файловый менеджер - Редактировать - /var/www/html/libraries/kunena/src/Upload/KunenaUpload.php
Ðазад
<?php /** * Kunena Component * * @package Kunena.Framework * @subpackage Upload * * @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved. * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL * @link https://www.kunena.org **/ namespace Kunena\Forum\Libraries\Upload; \defined('_JEXEC') or die; use Exception; use finfo; use Joomla\CMS\Factory; use Joomla\Filesystem\File; use Joomla\Filesystem\Folder; use Joomla\CMS\Language\Text; use Joomla\String\StringHelper; use Kunena\Forum\Libraries\Config\KunenaConfig; use Kunena\Forum\Libraries\Factory\KunenaFactory; use Kunena\Forum\Libraries\File\KunenaFile; use Kunena\Forum\Libraries\Image\KunenaImage; use Kunena\Forum\Libraries\Path\KunenaPath; use RuntimeException; use StdClass; /** * Class to handle file uploads. * * @since Kunena 4.0 */ class KunenaUpload { /** * @var array * @since Kunena 6.0 */ protected $validExtensions = []; /** * @var string * @since Kunena 6.0 */ protected $filename; /** * Get new instance of upload class. * * @param array $extensions List of allowed file extensions. * * @return KunenaUpload * * @since Kunena 6.0 */ public static function getInstance(array $extensions = []): KunenaUpload { $instance = new self(); if ($extensions) { $instance->addExtensions($extensions); } return $instance; } /** * Add file extensions to allowed list. * * @param array $extensions List of file extensions, supported values are like: zip, .zip, tar.gz, .tar.gz. * * @return $this * * @since Kunena 6.0 */ public function addExtensions(array $extensions): KunenaUpload { foreach ($extensions as $ext) { $ext = trim((string) $ext, ". \t\n\r\0\x0B"); if (!$ext) { continue; } $ext = '.' . $ext; $this->validExtensions[$ext] = $ext; } return $this; } /** * Upload a file via AJAX, supports chunks and fallback to regular file upload. * * @param array $options Upload options. * * @return array Updated options. * * @throws null * @since Kunena 6.0 */ public function ajaxUpload(array $options): array { static $defaults = [ 'completed' => false, 'filename' => null, 'size' => 0, 'mime' => null, 'hash' => null, 'chunkStart' => 0, 'chunkEnd' => 0, 'image_type' => null, ]; $options += $defaults; $exception = null; $in = null; $out = null; $size = 0; $outFile = null; $type = $options['mime']; // Look for the content type header if (isset($_SERVER['HTTP_CONTENT_TYPE'])) { $contentType = $_SERVER['HTTP_CONTENT_TYPE']; } elseif (isset($_SERVER['CONTENT_TYPE'])) { $contentType = $_SERVER['CONTENT_TYPE']; } else { $contentType = ''; } try { // Set filename for future queries. $this->filename = $options['filename']; $folder = $this->getFolder(); // Create target directory if it does not exist. if (!is_dir($folder) && !Folder::create($folder)) { throw new RuntimeException(Text::_('Failed to create upload directory.'), 500); } // Calculate temporary filename. $outFile = $this->getProtectedFile(); if ($options['chunkEnd'] > $options['size'] || $options['chunkStart'] > $options['chunkEnd']) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_EXTRA_CHUNK'), 400); } if (strpos($contentType, 'multipart') !== false) { // Older WebKit browsers didn't support multi-part in HTML5. $exception = $this->checkUpload($_FILES['file']); if ($exception) { throw $exception; } $in = fopen($_FILES['file']['tmp_name'], 'rb'); } else { // Multi-part upload. $in = fopen('php://input', 'rb'); } if (!$in) { throw new RuntimeException(Text::_('Failed to open upload input stream.'), 500); } // Open temporary file. $out = fopen($outFile, !$options['chunkStart'] ? 'wb' : 'r+b'); if (!$out) { throw new RuntimeException(Text::_('Failed to open upload output stream.'), 500); } // Get current size for the file. $stat = fstat($out); if (!$stat) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_STAT', $options['filename']), 500); } $size = $stat['size']; if ($options['chunkStart'] > $size) { throw new RuntimeException(Text::sprintf('Missing data chunk at location %d.', $size), 500); } fseek($out, $options['chunkStart']); while (!feof($in)) { // Set script execution time to 8 seconds in order to interrupt stalled file transfers (< 1kb/sec). // Not sure if it works, though, needs some testing. :) @set_time_limit(8); $buff = fread($in, 8192); if ($buff === false) { throw new RuntimeException(Text::_('Failed to read from upload input stream.'), 500); } $bytes = fwrite($out, $buff); if ($bytes === false) { throw new RuntimeException(Text::_('Failed to write into upload output stream.'), 500); } $size += $bytes; if ($options['image_type'] == 'avatar') { if (!$this->checkFileSizeAvatar($size)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_AVATAR_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } } else { if (stripos($type, 'image/') === false && stripos($type, 'image/') <= 0) { if (!$this->checkFileSizeFileAttachment($size)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } } if (stripos($type, 'image/') !== false && stripos($type, 'image/') >= 0) { if (!$this->checkFileSizeImageAttachment($size)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_IMAGE_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } } } } } catch (Exception $exception) { } // Reset script execution time. @set_time_limit(25); if ($in) { fclose($in); } if ($out) { fclose($out); } if ($exception instanceof Exception) { $this->cleanup(); throw $exception; } // Generate response. if ((\is_null($options['size']) && $size) || $size === $options['size']) { $options['size'] = (int) $size; $options['completed'] = true; } $options['chunkStart'] = (int) $size; if ($options['completed']) { $options['mime'] = KunenaFile::getMime($outFile); $options['hash'] = md5_file($outFile); } else { if ($size) { $options['mime'] = KunenaFile::getMime($outFile); } } return $options; } /** * Get upload folder. * * @return string Absolute path. * * @throws Exception * @since Kunena 6.0 */ public function getFolder(): string { $dir = KunenaPath::tmpdir(); return "{$dir}/uploads"; } /** * @param string $filename Original filename. * * @return string Path pointing to the protected file. * * @throws Exception * @since Kunena 6.0 */ public function getProtectedFile($filename = null): string { $filename = $filename ? $filename : $this->filename; return $this->getFolder() . '/' . $this->getProtectedFilename($filename); } /** * @param string $filename Original filename. * * @return string Protected filename. * * @throws Exception * @since Kunena 6.0 */ public function getProtectedFilename($filename = null): string { $filename = $filename ? $filename : $this->filename; $user = Factory::getApplication()->getIdentity(); $session = Factory::getApplication()->getSession(); $token = Factory::getApplication()->get('secret') . $user->id . $session->getToken(); list($name, $ext) = $this->splitFilename($filename); return md5("{$name}.{$token}.{$ext}"); } /** * Split filename by valid extension. * * @param string $filename Name of the file. * * @return array File parts: list($name, $extension). * * @throws RuntimeException * @since Kunena 6.0 */ public function splitFilename($filename = null): array { $filename = $filename ? $filename : $this->filename; if (!$filename) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_NO_FILE'), 400); } // Check if file extension matches any allowed extensions (case insensitive) foreach ($this->validExtensions as $ext) { $extension = StringHelper::substr($filename, -StringHelper::strlen($ext)); if (StringHelper::strtolower($extension) == StringHelper::strtolower($ext)) { // File must contain one letter before extension $name = StringHelper::substr($filename, 0, -StringHelper::strlen($ext)); $extension = StringHelper::substr($extension, 1); if (!$name) { break; } return [$name, $extension]; } } // Need to set the filename to null else it will delete a file at Joomla! root if it have the same name that the one uploaded $this->filename = null; throw new RuntimeException( Text::sprintf('COM_KUNENA_UPLOAD_ERROR_EXTENSION_FILE', implode(', ', $this->validExtensions)), 400 ); } /** * Check for upload errors. * * @param array $file Entry from $_FILES array. * * @return \RuntimeException|null * * @since Kunena 6.0 */ protected function checkUpload(array $file): ?RuntimeException { $exception = null; switch ($file['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_SIZE'), 400); break; case UPLOAD_ERR_PARTIAL: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_PARTIAL'), 400); break; case UPLOAD_ERR_NO_FILE: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_NO_FILE'), 400); break; case UPLOAD_ERR_NO_TMP_DIR: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_NO_TMP_DIR'), 500); break; case UPLOAD_ERR_CANT_WRITE: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_CANT_WRITE'), 500); break; case UPLOAD_ERR_EXTENSION: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_PHP_EXTENSION'), 500); break; default: $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_UNKNOWN'), 500); } if (!$exception && (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name']))) { $exception = new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_NOT_UPLOADED'), 400); } return $exception; } /** * Check if filesize on avatar which on going to be uploaded doesn't exceed the limits set by Kunena configuration * and Php configuration * * @param int $fileSize filesize * * @return boolean * @throws Exception * @since Kunena */ protected function checkFileSizeAvatar(int $fileSize) { if ($fileSize > \intval(KunenaConfig::getInstance()->avatarSize * 1024)) { return false; } return (int) max( 0, min( $this->toBytes(\ini_get('upload_max_filesize')), $this->toBytes(\ini_get('post_max_size')), $this->toBytes(\ini_get('memory_limit')) ) ); } /** * Convert value into bytes. * * @param string $value Value, for example: 1G, 10M, 120k... * * @return float Value in bytes. * * @since Kunena 6.0 */ public static function toBytes(string $value) { $base = log((int) $value, 1024); return round(pow(1024, $base - floor($base))); } /** * Check if fileSize on file which on going to be uploaded doesn't exceed the limits set by Kunena configuration * and PHP configuration * * @param int $fileSize The size of file in bytes * * @return integer * * @throws Exception * @since Kunena 6.0 */ protected function checkFileSizeFileAttachment(int $fileSize) { $file = $fileSize > KunenaConfig::getInstance()->fileSize * 1024; if ($file) { return false; } return (int) max( 0, min( $this->toBytes(\ini_get('upload_max_filesize')), $this->toBytes(\ini_get('post_max_size')), $this->toBytes(\ini_get('memory_limit')) ) ); } /** * Check if filesize on image file which on going to be uploaded doesn't exceed the limits set by Kunena * configuration and PHP configuration * * @param int $filesize The size of file in bytes * * @return boolean * @throws Exception * @since Kunena */ protected function checkFileSizeImageAttachment($filesize) { $image = $filesize > \intval(KunenaConfig::getInstance()->imageSize * 1024); if ($image) { return false; } return (int) max( 0, min( $this->toBytes(\ini_get('upload_max_filesize')), $this->toBytes(\ini_get('post_max_size')), $this->toBytes(\ini_get('memory_limit')) ) ); } /** * Clean up temporary file if it exists. * * @return void * * @since Kunena 6.0 */ public function cleanup(): void { if (!$this->filename || !is_file($this->filename)) { return; } @unlink($this->filename); } /** * Upload file by passing it by HTML input * * @param array $fileInput The file object returned by Joomla\Input\Input * @param string $destination The path of destination of file uploaded * @param string $type The type of file uploaded: attachment or avatar * * @return object * * @throws Exception * @since Kunena 6.0 */ public function upload(array $fileInput, string $destination, $type = 'attachment') { $file = new stdClass(); $file->ext = File::getExt($fileInput['name']); $file->ext = strtolower($file->ext); $file->size = $fileInput['size']; $config = KunenaFactory::getConfig(); if ($type != 'attachment' && $config->attachmentUtf8) { $file->tmp_name = $fileInput['tmp_name']; } else { $pathInfo = pathinfo($fileInput['tmp_name']); $file->tmp_name = $pathInfo['dirname'] . '/' . File::makeSafe($pathInfo['basename']); } $file->error = $fileInput['error']; $file->destination = $destination . '.' . $file->ext; $file->success = false; $file->isAvatar = false; if ($type == 'avatar') { $file->isAvatar = true; } if ($file->isAvatar) { if (!$this->checkFileSizeImage($file->size, 'avatar')) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_AVATAR_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } $avatarTypes = strtolower(KunenaConfig::getInstance()->avatarTypes); $a = explode(', ', $avatarTypes); if (!\in_array($file->ext, $a, true)) { throw new RuntimeException(Text::sprintf('COM_KUNENA_UPLOAD_ERROR_EXTENSION_FILE', implode(', ', $a)), 500); } } if (!is_uploaded_file($file->tmp_name)) { $exception = $this->checkUpload($fileInput); if ($exception) { throw $exception; } } elseif ($file->error != 0) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_NOT_UPLOADED'), 500); } // Check if file extension matches any allowed extensions (case insensitive) foreach ($this->validExtensions as $ext) { $extension = StringHelper::substr($file->tmp_name, -StringHelper::strlen($ext)); if (StringHelper::strtolower($extension) == StringHelper::strtolower($ext)) { // File must contain one letter before extension $name = StringHelper::substr($file->tmp_name, 0, -StringHelper::strlen($ext)); if (!$name) { throw new RuntimeException( Text::sprintf('COM_KUNENA_UPLOAD_ERROR_EXTENSION_FILE', implode(', ', $this->validExtensions)), 400 ); } } if (\extension_loaded('fileinfo')) { $finfo = new finfo(FILEINFO_MIME); $type = $finfo->file($file->tmp_name); } else { throw new RuntimeException("Fileinfo extension not loaded."); } if (!$file->isAvatar && stripos($type, 'image/') !== false) { if (!$this->checkFileSizeImageAttachment($file->size)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_IMAGE_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } } if (!$file->isAvatar && stripos($type, 'image/') !== true) { if (!$this->checkFileSizeFileAttachment($file->size)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_EXCEED_LIMIT_IN_CONFIGURATION'), 500); } } } KunenaImage::correctImageOrientation($file->tmp_name); if (!File::copy($file->tmp_name, $file->destination)) { throw new RuntimeException(Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_RIGHT_MEDIA_DIR'), 500); } unlink($file->tmp_name); KunenaPath::setPermissions($file->destination); $file->success = true; return $file; } /** * Check if fileSize on image file which on going to be uploaded doesn't exceed the limits set by Kunena * configuration and PHP configuration * * @param int $fileSize The size of file in bytes * @param string $image_type The type of image : avatar or attachment image * * @return boolean * * @throws Exception * @since Kunena 6.0 */ protected function checkFileSizeImage(int $fileSize, string $image_type) { if ($image_type == 'avatar') { $config_size = KunenaConfig::getInstance()->avatarSize; } else { $config_size = KunenaConfig::getInstance()->imageSize; } $image = $fileSize > \intval($config_size * 1024); if ($image) { return false; } return (int) max( 0, min( $this->toBytes(\ini_get('upload_max_fileSize')), $this->toBytes(\ini_get('post_max_size')), $this->toBytes(\ini_get('memory_limit')) ) ); } /** * Convert into human readable format bytes to kB, MB, GB * * @param integer $bytes size in bytes * @param null $force_unit a definitive unit * @param null $format the return string format * @param boolean $si whether to use SI prefixes or IEC * * @return string * * @since Kunena 6.0 */ public function bytes(int $bytes, $force_unit = null, $format = null, $si = true): string { // Format string $format = ($format === null) ? '%01.2f %s' : (string) $format; $units = [Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_WEIGHT_BYTES'), Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_WEIGHT_KB'), Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_WEIGHT_MB'), Text::_('COM_KUNENA_UPLOAD_ERROR_FILE_WEIGHT_GB'), ]; $mod = 1024; // Determine unit to use if (($power = array_search((string) $force_unit, $units)) === false) { $power = ($bytes > 0) ? floor(log($bytes, $mod)) : 0; } return sprintf($format, $bytes / pow($mod, $power), $units[$power]); } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка