![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/AssetBundle/Entity/ |
<?php namespace Mautic\AssetBundle\Entity; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\ApiBundle\Serializer\Driver\ApiMetadataDriver; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; use Mautic\CoreBundle\Entity\FormEntity; use Mautic\CoreBundle\Helper\FileHelper; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; class Asset extends FormEntity { /** * @var int */ private $id; /** * @var string */ private $title; /** * @var string|null */ private $description; /** * @var string|null */ private $storageLocation = 'local'; /** * @var string|null */ private $path; /** * @var string|null */ private $remotePath; /** * @var string|null */ private $originalFileName; /** * @var File */ private $file; /** * Holds upload directory. */ private $uploadDir; /** * Holds max size of uploaded file. */ private $maxSize; /** * Temporary location when asset file is beeing updated. * We need to keep the old file till we are sure the new * one is stored correctly. */ private $temp; /** * Temporary ID used for file upload and validations * before the actual ID is known. */ private $tempId; /** * Temporary file name used for file upload and validations * before the actual ID is known. */ private $tempName; /** * @var string */ private $alias; /** * @var string */ private $language = 'en'; /** * @var \DateTimeInterface|null */ private $publishUp; /** * @var \DateTimeInterface|null */ private $publishDown; /** * @var int */ private $downloadCount = 0; /** * @var int */ private $uniqueDownloadCount = 0; /** * @var int */ private $revision = 1; /** * @var \Mautic\CategoryBundle\Entity\Category|null **/ private $category; /** * @var string|null */ private $extension; /** * @var string|null */ private $mime; /** * @var int|null */ private $size; /** * @var string|null */ private $downloadUrl; /** * @var bool|null */ private $disallow = true; public static function loadMetadata(ORM\ClassMetadata $metadata): void { $builder = new ClassMetadataBuilder($metadata); $builder->setTable('assets') ->setCustomRepositoryClass(AssetRepository::class) ->addIndex(['alias'], 'asset_alias_search'); $builder->addIdColumns('title'); $builder->addField('alias', 'string'); $builder->createField('storageLocation', 'string') ->columnName('storage_location') ->nullable() ->build(); $builder->createField('path', 'string') ->nullable() ->build(); $builder->createField('remotePath', Types::TEXT) ->columnName('remote_path') ->nullable() ->build(); $builder->createField('originalFileName', Types::TEXT) ->columnName('original_file_name') ->nullable() ->build(); $builder->createField('language', 'string') ->columnName('lang') ->build(); $builder->addPublishDates(); $builder->createField('downloadCount', 'integer') ->columnName('download_count') ->build(); $builder->createField('uniqueDownloadCount', 'integer') ->columnName('unique_download_count') ->build(); $builder->addField('revision', 'integer'); $builder->addCategory(); $builder->createField('extension', 'string') ->nullable() ->build(); $builder->createField('mime', 'string') ->nullable() ->build(); $builder->createField('size', 'integer') ->nullable() ->build(); $builder->createField('disallow', 'boolean') ->nullable() ->build(); } /** * Prepares the metadata for API usage. */ public static function loadApiMetadata(ApiMetadataDriver $metadata): void { $metadata->setGroupPrefix('asset') ->addListProperties( [ 'id', 'title', 'alias', 'category', 'description', ] ) ->addProperties( [ 'language', 'publishUp', 'publishDown', 'downloadCount', 'uniqueDownloadCount', 'revision', 'extension', 'mime', 'size', 'downloadUrl', 'storageLocation', 'disallow', ] ) ->build(); } /** * Clone magic function. */ public function __clone() { $this->id = null; parent::__clone(); } /** * Get id. * * @return int */ public function getId() { return $this->id; } /** * Sets file. */ public function setFile(File $file = null): void { $this->file = $file; // check if we have an old asset path if (isset($this->path)) { // store the old name to delete after the update $this->temp = $this->path; $this->path = null; } } /** * Get file. * * @return UploadedFile */ public function getFile() { // if file is not set, try to find it at temp folder if ($this->isLocal() && empty($this->file)) { $tempFile = $this->loadFile(true); if ($tempFile) { $this->setFile($tempFile); } } return $this->file; } /** * Set title. * * @param string $title * * @return Asset */ public function setTitle($title) { $this->isChanged('title', $title); $this->title = $title; return $this; } /** * Get title. * * @return string */ public function getTitle() { return $this->title; } /** * @return mixed */ public function getExtension() { return $this->extension; } /** * @param mixed $extension */ public function setExtension($extension): void { $this->extension = $extension; } /** * @return mixed */ public function getMime() { return $this->mime; } /** * @param mixed $mime */ public function setMime($mime): void { $this->mime = $mime; } /** * Set originalFileName. * * @param string $originalFileName * * @return Asset */ public function setOriginalFileName($originalFileName) { $this->isChanged('originalFileName', $originalFileName); $this->originalFileName = $originalFileName; return $this; } /** * Get originalFileName. * * @return string */ public function getOriginalFileName() { return $this->originalFileName; } /** * Set storage location. * * @param string $storageLocation * * @return Asset */ public function setStorageLocation($storageLocation) { $this->isChanged('storageLocation', $storageLocation); $this->storageLocation = $storageLocation; return $this; } /** * Get storage location. * * @return string */ public function getStorageLocation() { if (null === $this->storageLocation) { $this->storageLocation = 'local'; } return $this->storageLocation; } /** * Set path. * * @param string $path * * @return Asset */ public function setPath($path) { $this->isChanged('path', $path); $this->path = $path; return $this; } /** * Get path. * * @return string */ public function getPath() { return $this->path; } /** * Set remote path. * * @param string $remotePath * * @return Asset */ public function setRemotePath($remotePath) { $this->isChanged('remotePath', $remotePath); $this->remotePath = $remotePath; return $this; } /** * Get remote path. * * @return string */ public function getRemotePath() { return $this->remotePath; } /** * Set alias. * * @param string $alias * * @return Asset */ public function setAlias($alias) { $this->isChanged('alias', $alias); $this->alias = $alias; return $this; } /** * Get alias. * * @return string */ public function getAlias() { return $this->alias; } /** * Set publishUp. * * @param \DateTime $publishUp * * @return Asset */ public function setPublishUp($publishUp) { $this->isChanged('publishUp', $publishUp); $this->publishUp = $publishUp; return $this; } /** * Get publishUp. * * @return \DateTimeInterface */ public function getPublishUp() { return $this->publishUp; } /** * Set publishDown. * * @param \DateTimeInterface $publishDown * * @return Asset */ public function setPublishDown($publishDown) { $this->isChanged('publishDown', $publishDown); $this->publishDown = $publishDown; return $this; } /** * Get publishDown. * * @return \DateTimeInterface */ public function getPublishDown() { return $this->publishDown; } /** * Set downloadCount. * * @param int $downloadCount * * @return Asset */ public function setDownloadCount($downloadCount) { $this->downloadCount = $downloadCount; return $this; } /** * Get downloadCount. * * @return int */ public function getDownloadCount() { return $this->downloadCount; } /** * Set revision. * * @param int $revision * * @return Asset */ public function setRevision($revision) { $this->revision = $revision; return $this; } /** * Get revision. * * @return int */ public function getRevision() { return $this->revision; } /** * Set language. * * @param string $language * * @return Asset */ public function setLanguage($language) { $this->isChanged('language', $language); $this->language = $language; return $this; } /** * Get language. * * @return string */ public function getLanguage() { return $this->language; } /** * Set category. * * @return Asset */ public function setCategory(\Mautic\CategoryBundle\Entity\Category $category = null) { $this->isChanged('category', $category); $this->category = $category; return $this; } /** * Get category. * * @return \Mautic\CategoryBundle\Entity\Category */ public function getCategory() { return $this->category; } /** * Set uniqueDownloadCount. * * @param int $uniqueDownloadCount * * @return Asset */ public function setUniqueDownloadCount($uniqueDownloadCount) { $this->uniqueDownloadCount = $uniqueDownloadCount; return $this; } /** * Get uniqueDownloadCount. * * @return int */ public function getUniqueDownloadCount() { return $this->uniqueDownloadCount; } public function setFileNameFromRemote(): void { $fileName = basename($this->getRemotePath()); $this->setOriginalFileName($fileName); // set the asset title as original file name if title is missing if (null === $this->getTitle()) { $this->setTitle($fileName); } } public function preUpload(): void { if (null !== $this->getFile()) { // set the asset title as original file name if title is missing if (null === $this->getTitle()) { $this->setTitle($this->file->getClientOriginalName()); } $filename = sha1(uniqid(mt_rand(), true)); $extension = $this->getFile()->guessExtension(); if (empty($extension)) { // get it from the original name $extension = pathinfo($this->originalFileName, PATHINFO_EXTENSION); } $this->path = $filename.'.'.$extension; } elseif ($this->isRemote() && null !== $this->getRemotePath()) { $this->setFileNameFromRemote(); } } public function upload(): void { // the file property can be empty if the field is not required if (null === $this->getFile()) { // check for the remote and set type data if ($this->isRemote()) { $this->setFileInfoFromFile(); } return; } // move takes the target directory and then the // target filename to move to $this->getFile()->move($this->getUploadDir(), $this->path); $filePath = $this->getUploadDir().'/'.$this->temp; $this->setFileInfoFromFile(); // check if we have an old asset if (isset($this->temp) && file_exists($filePath)) { // delete the old asset unlink($filePath); // clear the temp asset path $this->temp = null; } // Remove temporary folder and files $fs = new Filesystem(); $fs->remove($this->getAbsoluteTempDir()); // clean up the file property as you won't need it anymore $this->file = null; } /** * Remove a file. */ public function setFileInfoFromFile(): void { // get some basic information about the file type $fileInfo = $this->getFileInfo(); if (!is_array($fileInfo)) { return; } // set the mime and extension column values $this->setExtension($fileInfo['extension']); $this->setMime($fileInfo['mime']); $this->setSize($fileInfo['size']); } /** * Remove a file. * * @param bool $temp >> regular uploaded file or temporary */ public function removeUpload($temp = false): void { if ($temp) { $file = $this->getAbsoluteTempPath(); } else { $file = $this->getAbsolutePath(); } if ($file && file_exists($file)) { unlink($file); } } /** * Returns absolute path to the file. * * @return string */ public function getAbsolutePath() { return null === $this->path ? null : $this->getUploadDir().'/'.$this->path; } /** * Returns absolute path to temporary file. * * @return string */ public function getAbsoluteTempPath() { return null === $this->tempId || null === $this->tempName ? null : $this->getAbsoluteTempDir().'/'.$this->tempName; } /** * Returns absolute path to temporary file. * * @return string */ public function getAbsoluteTempDir() { return null === $this->tempId ? null : $this->getUploadDir().'/tmp/'.$this->tempId; } /** * Returns absolute path to upload dir. * * @return string */ protected function getUploadDir() { if ($this->uploadDir) { return $this->uploadDir; } return 'media/files'; } /** * Set uploadDir. * * @param string $uploadDir * * @return Asset */ public function setUploadDir($uploadDir) { $this->uploadDir = $uploadDir; return $this; } /** * Returns maximal uploadable size in bytes. * If not set, 6000000 is default. * * @return string */ protected function getMaxSize() { if ($this->maxSize) { return $this->maxSize; } return 6_000_000; } /** * Set max size. * * @param string $maxSize * * @return Asset */ public function setMaxSize($maxSize) { $this->maxSize = $maxSize; return $this; } /** * Returns file extension. * * @return string */ public function getFileType() { if (!empty($this->extension) && empty($this->changes['originalFileName'])) { return $this->extension; } if ($this->isRemote()) { return pathinfo(parse_url($this->getRemotePath(), PHP_URL_PATH), PATHINFO_EXTENSION); } if (null === $this->loadFile()) { return ''; } return $this->loadFile()->guessExtension(); } /** * Returns some file info. * * @return array */ public function getFileInfo() { $fileInfo = []; if ($this->isRemote()) { $ch = curl_init($this->getRemotePath()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_exec($ch); // build an array of handy info $fileInfo['mime'] = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $fileInfo['extension'] = $this->getFileType(); $fileInfo['size'] = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); return $fileInfo; } if (null === $this->loadFile()) { return ''; } // return an array of file type info $fileInfo['mime'] = $this->loadFile()->getMimeType(); $fileInfo['extension'] = $this->getFileType(); $fileInfo['size'] = $this->getSize(false, true); return $fileInfo; } /** * Returns file mime type. * * @return string */ public function getFileMimeType() { if ($this->isRemote()) { $ch = curl_init($this->getRemotePath()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); curl_exec($ch); return curl_getinfo($ch, CURLINFO_CONTENT_TYPE); } if (null === $this->loadFile()) { return ''; } return $this->loadFile()->getMimeType(); } /** * Returns Font Awesome icon class based on file type. */ public function getIconClass(): string { $fileType = $this->getFileType(); // return missing file icon if file type is empty if (!$fileType) { return 'fa fa-ban'; } $fileTypes = $this->getFileExtensions(); // Search for icon name by file extension. foreach ($fileTypes as $icon => $extensions) { if (in_array($fileType, $extensions)) { return 'fa fa-file-'.$icon.'-o'; } } // File extension is unknown, display general file icon. return 'fa fa-file-o'; } /** * Decides if an asset is image displayable by browser. */ public function isImage(): bool { $fileType = strtolower($this->getFileType()); if (!$fileType) { return false; } $imageTypes = ['jpg', 'jpeg', 'png', 'gif']; if (in_array($fileType, $imageTypes)) { return true; } return false; } /** * Returns array of common extensions. * * @return array<string, string[]> */ public function getFileExtensions(): array { return [ 'excel' => [ 'xlsx', 'xlsm', 'xlsb', 'xltx', 'xltm', 'xls', 'xlt', ], 'word' => [ 'doc', 'docx', 'docm', 'dotx', ], 'pdf' => [ 'pdf', ], 'audio' => [ 'mp3', ], 'archive' => [ 'zip', 'rar', 'iso', 'tar', 'gz', '7z', ], 'image' => [ 'jpg', 'jpeg', 'png', 'gif', 'ico', 'bmp', 'psd', ], 'text' => [ 'txt', 'pub', ], 'code' => [ 'php', 'js', 'json', 'yaml', 'xml', 'html', 'htm', 'sql', ], 'powerpoint' => [ 'ppt', 'pptx', 'pptm', 'xps', 'potm', 'potx', 'pot', 'pps', 'odp', ], 'video' => [ 'wmv', 'avi', 'mp4', 'mkv', 'mpeg', ], ]; } /** * Load the file object from it's path. * * @return File|null */ public function loadFile($temp = false) { if ($temp) { $path = $this->getAbsoluteTempPath(); } else { $path = $this->getAbsolutePath(); } if (!$path || !file_exists($path)) { return null; } try { $file = new File($path); } catch (FileNotFoundException) { $file = null; } return $file; } /** * Load content of the file from it's path. */ public function getFileContents(): string|bool { $path = $this->getFilePath(); return file_get_contents($path); } /** * Get the path to the file; a URL if remote or full file path if local. * * @return string */ public function getFilePath() { return $this->isRemote() ? $this->getRemotePath() : $this->getAbsolutePath(); } /** * @return mixed */ public function getDescription() { return $this->description; } /** * @param mixed $description */ public function setDescription($description): void { $this->description = $description; } public static function loadValidatorMetadata(ClassMetadata $metadata): void { // Add a constraint to manage the file upload data $metadata->addConstraint(new Assert\Callback([self::class, 'validateFile'])); } /** * Validator to ensure proper data for the file fields. * * @param Asset $object Entity object to validate * @param ExecutionContextInterface $context Context object */ public static function validateFile($object, ExecutionContextInterface $context): void { if ($object->isLocal()) { $tempName = $object->getTempName(); $path = $object->getPath(); // If the object is stored locally, we should have file data if ($object->isNew() && null === $tempName && null === $path) { $context->buildViolation('mautic.asset.asset.error.missing.file') ->atPath('tempName') ->setTranslationDomain('validators') ->addViolation(); } if (null === $object->getTitle()) { $context->buildViolation('mautic.asset.asset.error.missing.title') ->atPath('title') ->setTranslationDomain('validators') ->addViolation(); } // Unset any remote file data $object->setRemotePath(null); } elseif ($object->isRemote()) { // If the object is stored remotely, we should have a remote path if (null === $object->getRemotePath()) { $context->buildViolation('mautic.asset.asset.error.missing.remote.path') ->atPath('remotePath') ->setTranslationDomain('validators') ->addViolation(); } // Unset any local file data $object->setPath(null); } } /** * Set temporary ID. * * @param string $tempId * * @return Asset */ public function setTempId($tempId) { $this->tempId = $tempId; return $this; } /** * Get temporary ID. * * @return string */ public function getTempId() { return $this->tempId; } /** * Set temporary file name. * * @param string $tempName * * @return Asset */ public function setTempName($tempName) { $this->tempName = $tempName; return $this; } /** * Get temporary file name. * * @return string */ public function getTempName() { return $this->tempName; } /** * @param bool $humanReadable * @param bool $forceUpdate * @param string $inUnit * * @return float|string */ public function getSize($humanReadable = true, $forceUpdate = false, $inUnit = '') { if (empty($this->size) || $forceUpdate) { // Try to fetch it if ($this->isRemote()) { $ch = curl_init($this->getRemotePath()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_exec($ch); $this->setSize(round(curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD))); } if (null === $this->loadFile()) { return 0; } $this->setSize(round($this->loadFile()->getSize())); } return ($humanReadable) ? static::convertBytesToHumanReadable($this->size, $inUnit) : $this->size; } /** * @param mixed $size * * @return Asset */ public function setSize($size) { $this->size = $size; return $this; } /** * Get value from PHP configuration with special handling of -1. * * @param string $setting * @param bool|true $convertToBytes */ public static function getIniValue($setting, $convertToBytes = true): int { $value = ini_get($setting); if (-1 == $value || 0 === $value) { return PHP_INT_MAX; } if ($convertToBytes) { $value = FileHelper::convertPHPSizeToBytes($value); } return (int) $value; } /** * @param string $unit */ public static function convertBytesToHumanReadable($size, $unit = ''): string { [$number, $unit] = self::convertBytesToUnit($size, $unit); // Format number $number = number_format($number, 2); // Remove trailing .00 $number = str_contains($number, '.') ? rtrim(rtrim($number, '0'), '.') : $number; return $number.' '.$unit; } /** * @param string $unit */ public static function convertBytesToUnit($size, $unit = ''): array { $unit = strtoupper($unit); if ((!$unit && $size >= 1 << 30) || 'GB' == $unit || 'G' == $unit) { return [$size / (1 << 30), 'GB']; } if ((!$unit && $size >= 1 << 20) || 'MB' == $unit || 'M' == $unit) { return [$size / (1 << 20), 'MB']; } if ((!$unit && $size >= 1 << 10) || 'KB' == $unit || 'K' == $unit) { return [$size / (1 << 10), 'KB']; } // Add zero to remove useless .00 return [$size, 'bytes']; } /** * @return string|null */ public function getDownloadUrl() { return $this->downloadUrl; } /** * @param string|null $downloadUrl * * @return Asset */ public function setDownloadUrl($downloadUrl) { $this->downloadUrl = $downloadUrl; return $this; } public function isLocal(): bool { return 'local' === $this->storageLocation; } public function isRemote(): bool { return 'remote' === $this->storageLocation; } /** * @return bool */ public function getDisallow() { return $this->disallow; } /** * @param mixed $disallow */ public function setDisallow($disallow): void { $this->disallow = $disallow; } }