Rev 17260 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpnamespace LeadersLinked\Library;use LeadersLinked\Model\User;use LeadersLinked\Model\UserProfile;use LeadersLinked\Model\Company;use LeadersLinked\Model\Group;class Storage{const FILE_TYPE_IMAGE = 'image';const FILE_TYPE_VIDEO = 'video';const FILE_TYPE_DOCUMENT = 'document';const TYPE_DEFAULT = 'default';const TYPE_CHAT = 'chat';const TYPE_GROUP = 'group';const TYPE_USER = 'user';const TYPE_IMAGE = 'image';const TYPE_JOB = 'job';const TYPE_MEDIA = 'media';const TYPE_COMPANY = 'company';const TYPE_FEED = 'feed';const TYPE_POST = 'post';const TYPE_MICROLEARNING_TOPIC = 'topic';const TYPE_MICROLEARNING_CAPSULE = 'capsule';const TYPE_MICROLEARNING_SLIDE = 'slide';const TYPE_MICROLEARNING_ACCESS_FOR_STUDENTS = 'access-for-students';const TYPE_JOB_DESCRIPTION = 'jobdesc';const TYPE_SELF_EVALUATION = 'selfval';const TYPE_PERFORMANCE_EVALUATION = 'perfeva';const TYPE_RECRUITMENT_SELECTION = 'recrsel';const TYPE_PLANNING_OBJECTIVES_AND_GOALS = 'plannig';const TYPE_MESSAGE = 'message';const TYPE_SURVEY = 'survey';const TYPE_NETWORK = 'network';const TYPE_DAILY_PULSE = 'dailpuls';const TYPE_ENGAGEMENT_REWARD = 'engarewr';const TYPE_KNOWLEDGE_AREA = 'knowarea';const TYPE_MY_COACH = 'mycoach';const TYPE_HABIT_EMOJI = 'habit-emoji';const TYPE_HABIT_CONTENT = 'habit-content';/**** @var\LeadersLinked\Library\Storage*/private static $_instance;/**** @var array*/private $config;/**** @var \Laminas\Db\Adapter\AdapterInterface*/private $adapter;/**** @var string*/private $tempPath;/**** @var string*/private $storagePath;/**** @var array*/private $currentFile;/**** @var array*/private $files;/**** @param array $config* @param \Laminas\Db\Adapter\AdapterInterface $adapter*/private function __construct($config, $adapter){$this->config = $config;$this->adapter = $adapter;$this->currentFile = [];$this->storagePath = 'data' . DIRECTORY_SEPARATOR . 'storage';if (! file_exists($this->storagePath)) {mkdir($this->storagePath, 0775, true);}$this->tempPath = 'data' . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'tmp';if (! file_exists($this->tempPath)) {mkdir($this->tempPath, 0775, true);}}/**** @param array $config* @param \Laminas\Db\Adapter\AdapterInterface $adapter* @return \LeadersLinked\Library\Storage*/public static function getInstance($config, $adapter){if (self::$_instance == null) {self::$_instance = new Storage($config, $adapter);}return self::$_instance;}/**** @return string*/public function getFullPathImageDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image.jpg';}/**** @return string*/public function getFullPathImageUserDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-user.jpg';}/**** @return string*/public function getFullPathImageUserPofileDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-user-profile.png';}/**** @return string*/public function getFullPathImageUserCoverDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-cover.jpg';}/**** @return string*/public function getFullPathImageCompanyDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-company.jpg';}/**** @return string*/public function getFullPathImageCompanyCoverDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-cover.jpg';}/**** @return string*/public function getFullPathImageGroupDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-group.jpg';}/**** @return string*/public function getFullPathImageGroupCoverDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'no-image-cover.jpg';}/**** @return string*/public function getFullPathImageCompanyHeaderPdfDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR . 'company-header.png';}/**** @return string*/public function getFullPathImageCompanyFooterPdfDefault(){return $this->storagePath . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR . 'company-footer.png';}/**** @return string*/public function getStoagePath(){return $this->storagePath;}/**** @return string*/public function getTempPath(){return $this->tempPath;}/**** @return array*/public function getCurrentFile(){return $this->currentFile;}/**** @param array $currentFile*/public function setCurrentFile($currentFile){$this->currentFile = $currentFile;}/**** @param array $filename*/public function setCurrentFilename($filename){if (empty($this->files)) {if (isset($_FILES[$filename]) && empty($_FILES[$filename]['error'])) {$this->currentFile = $_FILES[$filename];} else {$this->currentFile = [];}} else {if (isset($this->files[$filename]) && empty($this->files[$filename]['error'])) {$this->currentFile = $this->files[$filename];} else {$this->currentFile = [];}}return !empty($this->currentFile);}/**** @return boolean*/public function hasFile(){return !empty($this->currentFile);}/**** @param array $files*/public function setFiles($files){$this->files = $files;}/**** @param string $type* @param string $code* @param string $filename* @return string*/public function composePathToFilename($type, $code, $filename){$path = $this->getPathByType($type);$path = $path . DIRECTORY_SEPARATOR . $code;if (! file_exists($path)) {mkdir($path, 0775, true);}return $path . DIRECTORY_SEPARATOR . $filename;}/**** @param string $type* @param string $code* @return string*/public function composePathToDirectory($type, $code){$path = $this->getPathByType($type);$path = $path . DIRECTORY_SEPARATOR . $code;if (! file_exists($path)) {mkdir($path, 0775, true);}return $path;}/*** Private helper to get a presigned URL for an entity's image/cover or its default.** @param string $entityType The type of the entity (e.g., self::TYPE_USER).* @param string $entityUuid The UUID of the entity.* @param string|null $imageFilename The filename of the image/cover, if it exists.* @param string $defaultImageMethodName The name of the method in this class to get the full path to the default image.* @return string The presigned URL.*/private function _getProcessedImageOrCoverUrl($entityType, $entityUuid, $imageFilename, $defaultImageMethodName){if ($imageFilename) {$remoto = $this->composePathToFilename($entityType, $entityUuid, $imageFilename);if (file_exists($remoto)) {return $this->getPresignedUrl($remoto);}}// If imageFilename is null/empty, or the specific file doesn't exist, use the default.$defaultFullPath = $this->$defaultImageMethodName();return $this->getPresignedUrl($defaultFullPath);}/**** @param User $user* @return string*/public function getUserImage($user){return $this->_getProcessedImageOrCoverUrl(self::TYPE_USER, $user->uuid, $user->image, 'getFullPathImageUserDefault');}/**** @param User $user* @return string*/public function getUserImageForCodeAndFilename($code, $filename){return $this->_getProcessedImageOrCoverUrl(self::TYPE_USER, $code, $filename, 'getFullPathImageUserDefault');}/**** @param User $user* @param UserProfile $userProfile* @return string*/public function getUserProfileImage($user, $userProfile){return $this->_getProcessedImageOrCoverUrl(self::TYPE_USER, $user->uuid, $userProfile->image, 'getFullPathImageUserPofileDefault');}/**** @param User $user* @param UserProfile $userProfile* @return string*/public function getUserProfileCover($user, $userProfile){return $this->_getProcessedImageOrCoverUrl(self::TYPE_USER, $user->uuid, $userProfile->cover, 'getFullPathImageUserCoverDefault');}/**** @param Company $company* @return string*/public function getCompanyImage($company){return $this->_getProcessedImageOrCoverUrl(self::TYPE_COMPANY, $company->uuid, $company->image, 'getFullPathImageCompanyDefault');}/**** @param string $code* @param string $filename* @return string*/public function getCompanyImageForCodeAndFilename($code, $filename){return $this->_getProcessedImageOrCoverUrl(self::TYPE_COMPANY, $code, $filename, 'getFullPathImageCompanyDefault');}/**** @param Company $company* @return string*/public function getCompanyCover($company){return $this->_getProcessedImageOrCoverUrl(self::TYPE_COMPANY, $company->uuid, $company->cover, 'getFullPathImageCompanyCoverDefault');}/**** @param Group $group* @return string*/public function getGroupImage($group){return $this->_getProcessedImageOrCoverUrl(self::TYPE_GROUP, $group->uuid, $group->image, 'getFullPathImageGroupDefault');}/**** @param string $code* @param string $filename* @return string*/public function getGroupImageForCodeAndFilename($code, $filename){return $this->_getProcessedImageOrCoverUrl(self::TYPE_COMPANY, $code, $filename, 'getFullPathImageGroupDefault');}/**** @param Group $group* @return string*/public function getGroupCover($group){return $this->_getProcessedImageOrCoverUrl(self::TYPE_COMPANY, $group->uuid, $group->cover, 'getFullPathImageGroupCoverDefault');}/**** @param Group $group* @return string*/public function getGenericImage($path, $code, $filename){$remoto = $path . DIRECTORY_SEPARATOR . $code . DIRECTORY_SEPARATOR . $filename;if (file_exists($remoto)) {return $this->getPresignedUrl($remoto);}$remoto = $this->getFullPathImageDefault();return $this->getPresignedUrl($remoto);}/**** @param string $path* @param string $code,* @param string $filename* @return string*/public function getGenericFile($path, $code, $filename){$remoto = $path . DIRECTORY_SEPARATOR . $code . DIRECTORY_SEPARATOR . $filename;if (file_exists($remoto)) {if ($code == 'd8e6c5de-52a6-4c28-bdce-4ba2823ba841') {error_log('getGenericFile = ' . $remoto);}return $this->getPresignedUrl($remoto);}return;}public function getPathDefault(){return $this->getPathByType(self::TYPE_DEFAULT);}public function getPathChat(){return $this->getPathByType(self::TYPE_CHAT);}public function getPathGroup(){return $this->getPathByType(self::TYPE_GROUP);}public function getPathUser(){return $this->getPathByType(self::TYPE_USER);}public function getPathImage(){return $this->getPathByType(self::TYPE_IMAGE);}public function getPathJob(){return $this->getPathByType(self::TYPE_JOB);}public function getPathCompany(){return $this->getPathByType(self::TYPE_COMPANY);}public function getPathFeed(){return $this->getPathByType(self::TYPE_FEED);}public function getPathMedia(){return $this->getPathByType(self::TYPE_MEDIA);}public function getPathPost(){return $this->getPathByType(self::TYPE_POST);}public function getPathMicrolearningTopic(){return $this->getPathByType(self::TYPE_MICROLEARNING_TOPIC);}public function getPathMicrolearningCapsule(){return $this->getPathByType(self::TYPE_MICROLEARNING_CAPSULE);}public function getPathMicrolearningSlide(){return $this->getPathByType(self::TYPE_MICROLEARNING_SLIDE);}public function getPathJobDescription(){return $this->getPathByType(self::TYPE_JOB_DESCRIPTION);}public function getPathSelfEvaluation(){return $this->getPathByType(self::TYPE_SELF_EVALUATION);}public function getPathPerformanceEvaluation(){return $this->getPathByType(self::TYPE_PERFORMANCE_EVALUATION);}public function getPathRecruitmentSelection(){return $this->getPathByType(self::TYPE_RECRUITMENT_SELECTION);}public function getPathPlanningObjectivesAndGoals(){return $this->getPathByType(self::TYPE_PLANNING_OBJECTIVES_AND_GOALS);}public function getPathMessage(){return $this->getPathByType(self::TYPE_MESSAGE);}public function getPathSurvey(){return $this->getPathByType(self::TYPE_SURVEY);}public function getPathNetwork(){return $this->getPathByType(self::TYPE_NETWORK);}public function getPathDailyPulse(){return $this->getPathByType(self::TYPE_DAILY_PULSE);}public function getPathEngagementReward(){return $this->getPathByType(self::TYPE_ENGAGEMENT_REWARD);}public function getPathKnowledgeArea(){return $this->getPathByType(self::TYPE_KNOWLEDGE_AREA);}public function getPathMyCoach(){return $this->getPathByType(self::TYPE_MY_COACH);}public function getPathHabitEmoji(){return $this->getPathByType(self::TYPE_HABIT_EMOJI);}public function getPathHabitContent(){return $this->getPathByType(self::TYPE_HABIT_CONTENT);}public function getPathByType($type){switch ($type) {case self::TYPE_DEFAULT:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'default';break;case self::TYPE_CHAT:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'chat';break;case self::TYPE_GROUP:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'group';break;case self::TYPE_USER:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'user';break;case self::TYPE_IMAGE:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'image';break;case self::TYPE_JOB:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'job';break;case self::TYPE_COMPANY:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'company';break;case self::TYPE_FEED:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'feed';break;case self::TYPE_MEDIA:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'media';break;case self::TYPE_POST:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'post';break;case self::TYPE_MICROLEARNING_TOPIC:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'microlearning' . DIRECTORY_SEPARATOR . 'topic';break;case self::TYPE_MICROLEARNING_CAPSULE:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'microlearning' . DIRECTORY_SEPARATOR . 'capsule';break;case self::TYPE_MICROLEARNING_SLIDE:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'microlearning' . DIRECTORY_SEPARATOR . 'slide';break;case self::TYPE_JOB_DESCRIPTION:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'job-description';break;case self::TYPE_SELF_EVALUATION:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'self-evaluation';break;case self::TYPE_PERFORMANCE_EVALUATION:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'performance-evaluation';break;case self::TYPE_RECRUITMENT_SELECTION:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'recruitment-selection';break;case self::TYPE_PLANNING_OBJECTIVES_AND_GOALS:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'planning-objectives-and-goals';break;case self::TYPE_MESSAGE:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'message';break;case self::TYPE_SURVEY:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'survey';break;case self::TYPE_NETWORK:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'network';break;case self::TYPE_DAILY_PULSE:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'daily-pulse';break;case self::TYPE_ENGAGEMENT_REWARD:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'engagement-reward';break;case self::TYPE_KNOWLEDGE_AREA:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'knowledge-area';break;case self::TYPE_MY_COACH:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'my-coach';break;case self::TYPE_HABIT_EMOJI:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'habit' . DIRECTORY_SEPARATOR . 'emoji';break;case self::TYPE_HABIT_CONTENT:$path = $this->storagePath . DIRECTORY_SEPARATOR . 'habit' . DIRECTORY_SEPARATOR . 'content';break;default:$path = $this->storagePath;break;}if (! file_exists($path)) {mkdir($path, 0775, true);}return $path;}/**** @param string $path* @param string $code* @param string $filename* @return string*/public function deleteFile($path, $code, $filename){$remoto = $path . DIRECTORY_SEPARATOR . $code . DIRECTORY_SEPARATOR . $filename;if (file_exists($remoto)) {return unlink($remoto);} else {return true;}}/**** @param string $type* @param string $code* @return boolean*/public function deleteDirectory($type, $code){$path = $this->getPathByType($type);$remoto = $path . DIRECTORY_SEPARATOR . $code;if (file_exists($remoto)) {$this->deleteDirectoryRecursive($remoto);return true;} else {return true;}}/**** @param string $dir*/private function deleteDirectoryRecursive($dir){if (is_dir($dir)) {$objects = scandir($dir);foreach ($objects as $object) {if ($object != '.' && $object != '..') {$s = $dir . DIRECTORY_SEPARATOR . $object;if (is_dir($s) && ! is_link($s)) {$this->deleteDirectoryRecursive($s);} else {unlink($s);}}}rmdir($dir);}}/**** @param string $path* @param string $code* @param string $local_filename* @return boolean*/public function putFile($source_file, $target_file){return rename($source_file, $target_file);}/**** @param string $tempfile* @param string $path* @param string $code* @param string $filename* @return boolean*/public function moveUploadedFile($source_file, $target_file){return move_uploaded_file($source_file, $target_file);}/**** @param string $tempfile* @param string $path* @param string $code* @param string $filename* @return boolean*/public function copyFile($source_file, $target_file){return copy($source_file, $target_file);}/**** @param string $url* @return string*/public function getPresignedUrl($url){$code = hash('sha256', $url);$storageFileMapper = \LeadersLinked\Mapper\StorageFileMapper::getInstance($this->adapter);$storageFile = $storageFileMapper->fetchOneByCode($code);if (! $storageFile) {$storageFile = new \LeadersLinked\Model\StorageFile();$storageFile->code = $code;$storageFile->path = $url;$storageFile->salt = \LeadersLinked\Library\Functions::generatePassword(8);$storageFileMapper->insert($storageFile);}$url = 'https://' . $_SERVER['SERVER_NAME'] . '/storage/' . $code;return $url;}/**** @return @return void|string*/public function getFilenamePNG(){if ($this->currentFile) {$filename = $this->normalizeStringFilename($this->currentFile['name']);$path_parts = pathinfo($filename);return $path_parts['filename'] . '.png';} else {return;}}/**** @return @return void|string*/public function getTmpFilename(){if ($this->currentFile) {return $this->currentFile['tmp_name'];} else {return;}}/**** @return @return void|string*/public function getFilename(){if ($this->currentFile) {return $this->normalizeStringFilename($this->currentFile['name']);} else {return;}}/**** @return void|string*/public function getFileType(){if ($this->currentFile) {$tmp_name = $this->currentFile['tmp_name'];$mime_type = mime_content_type($tmp_name);if ($mime_type == 'image/jpg' || $mime_type == 'image/jpeg' || $mime_type == 'image/png') {return self::FILE_TYPE_IMAGE;} else if ($mime_type == 'video/quicktime' || $mime_type == 'video/webm' || $mime_type == 'video/mpeg' || $mime_type == 'video/mpg' || $mime_type == 'video/mp4') {return self::FILE_TYPE_VIDEO;} else if ($mime_type == 'application/pdf') {return self::FILE_TYPE_DOCUMENT;} else {return;}} else {return;}}/**** @return void|string*/public function getExtension(){if ($this->currentFile) {$path_parts = pathinfo($this->currentFile['name']);$ext = $path_parts['extension'];return $ext;} else {return;}}/*** Creates a new GD image resource with transparency settings for PNG.* @param int $width The width of the new image.* @param int $height The height of the new image.* @return \GdImage|false The image resource or false on failure.*/private function _createImageCanvas($width, $height){$new_image = imageCreateTrueColor($width, $height);if ($new_image === false) {error_log("_createImageCanvas: imageCreateTrueColor failed for dimensions {$width}x{$height}.");return false;}imageAlphaBlending($new_image, False);imageSaveAlpha($new_image, True);$transparent = imageColorAllocateAlpha($new_image, 0, 0, 0, 127);if ($transparent === false) {error_log("_createImageCanvas: imageColorAllocateAlpha failed.");imagedestroy($new_image);return false;}imagefill($new_image, 0, 0, $transparent);return $new_image;}/*** Saves a GD image resource as PNG, unlinks source, and cleans up image resource.* @param \GdImage $imageResource The GD image resource to save.* @param string $targetFilename The path to save the PNG file to.* @param string $sourceFilenameToUnlink The path to the source file to unlink.* @return bool True on success, false on failure.*/private function _savePngAndCleanup($imageResource, $targetFilename, $sourceFilenameToUnlink){$save_success = imagepng($imageResource, $targetFilename);imagedestroy($imageResource); // Clean up the image resourceif ($save_success) {if ($sourceFilenameToUnlink && file_exists($sourceFilenameToUnlink)) {unlink($sourceFilenameToUnlink);}return true;} else {error_log("_savePngAndCleanup: imagepng failed to save image to {$targetFilename}.");return false;}}/**** @param string $source* @param string $target_filename* @param int $target_width* @param int $target_height* @return boolean*/public function uploadImageResize($source_filename, $target_filename, $target_width, $target_height){try {$data = file_get_contents($source_filename);$img = imagecreatefromstring($data);if ($img) {list($source_width, $source_height) = getimagesize($source_filename);$width_ratio = $target_width / $source_width;$height_ratio = $target_height / $source_height;if ($width_ratio > $height_ratio) {$resized_width = $target_width;$resized_height = $source_height * $width_ratio;} else {$resized_height = $target_height;$resized_width = $source_width * $height_ratio;}$resized_width = round($resized_width);$resized_height = round($resized_height);$new_image = $this->_createImageCanvas($target_width, $target_height);if ($new_image === false) {imagedestroy($img);unlink($source_filename);return false;}imageCopyResampled($new_image, $img, 0, 0, 0, 0, $resized_width, $resized_height, $source_width, $source_height);imagedestroy($img); // Source image resource can be destroyed after resamplingreturn $this->_savePngAndCleanup($new_image, $target_filename, $source_filename);}unlink($source_filename);return false;} catch (\Throwable $e) {error_log($e->getTraceAsString());if (isset($img) && ($img instanceof \GdImage || is_resource($img))) {imagedestroy($img);}if (isset($new_image) && ($new_image instanceof \GdImage || is_resource($new_image))) {imagedestroy($new_image);}if (isset($source_filename) && file_exists($source_filename)) {unlink($source_filename);}return false;}}/**** @param string $source* @param string $target_filename* @param number $target_width* @param number $target_height* @return boolean*/public function uploadImageCrop($source_filename, $target_filename, $target_width, $target_height){try {$data = file_get_contents($source_filename);$img = imagecreatefromstring($data);if ($img) {list($source_width, $source_height) = getimagesize($source_filename);$width_ratio = $target_width / $source_width;$height_ratio = $target_height / $source_height;if ($width_ratio > $height_ratio) {$resized_width = $target_width;$resized_height = $source_height * $width_ratio;} else {$resized_height = $target_height;$resized_width = $source_width * $height_ratio;}$resized_width = round($resized_width);$resized_height = round($resized_height);$offset_width = round(($target_width - $resized_width) / 2);$offset_height = round(($target_height - $resized_height) / 2);$new_image = $this->_createImageCanvas($target_width, $target_height);if ($new_image === false) {imagedestroy($img);unlink($source_filename);return false;}imageCopyResampled($new_image, $img, $offset_width, $offset_height, 0, 0, $resized_width, $resized_height, $source_width, $source_height);imagedestroy($img);return $this->_savePngAndCleanup($new_image, $target_filename, $source_filename);}unlink($source_filename);return false;} catch (\Throwable $e) {error_log($e->getTraceAsString());if (isset($img) && ($img instanceof \GdImage || is_resource($img))) {imagedestroy($img);}if (isset($new_image) && ($new_image instanceof \GdImage || is_resource($new_image))) {imagedestroy($new_image);}if (isset($source_filename) && file_exists($source_filename)) {unlink($source_filename);}return false;}}/**** @param string $source* @param string $target_filename* @return boolean*/public function uploadImageWithOutChangeSize($source_filename, $target_filename){try {$data = file_get_contents($source_filename);$img = imagecreatefromstring($data);if ($img) {list($source_width, $source_height) = getimagesize($source_filename);$new_image = $this->_createImageCanvas($source_width, $source_height);if ($new_image === false) {imagedestroy($img);unlink($source_filename);return false;}imageCopyResampled($new_image, $img, 0, 0, 0, 0, $source_width, $source_height, $source_width, $source_height);imagedestroy($img);return $this->_savePngAndCleanup($new_image, $target_filename, $source_filename);}unlink($source_filename);return false;} catch (\Throwable $e) {error_log($e->getTraceAsString());if (isset($img) && ($img instanceof \GdImage || is_resource($img))) {imagedestroy($img);}if (isset($new_image) && ($new_image instanceof \GdImage || is_resource($new_image))) {imagedestroy($new_image);}if (isset($source_filename) && file_exists($source_filename)) {unlink($source_filename);}return false;}}public static function extractPosterFromVideo($source_filename, $target_filename){try {$cmd = "/usr/bin/ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width,duration $source_filename";$response = trim(shell_exec($cmd));$source_duration = 0;$lines = explode("\n", $response);foreach ($lines as $line) {$line = trim(strtolower($line));if (strpos($line, 'duration') !== false) {$values = explode('=', $line);$source_duration = intval(str_replace($values[1], '#', ''), 10);}}if ($source_duration == 0) {$second_extract = '00:00:02';} else {if ($source_duration > 10) {$second_extract = '00:00:10';} else {$second_extract = '00:00:02';}}$cmd = "/usr/bin/ffmpeg -y -i $source_filename -pix_fmt yuvj422p -an -ss $second_extract -f mjpeg -t 1 -r 1 -y $target_filename";exec($cmd);return true;} catch (\Throwable $e) {error_log($e->getTraceAsString());return false;}}/**** @param string $str* @return string*/public function normalizeStringFilename($str = ''){$basename = substr($str, 0, strrpos($str, '.'));$basename = str_replace('.', '-', $basename);$extension = substr($str, strrpos($str, '.'));$str = $basename . $extension;$str = strip_tags($str);$str = preg_replace('/[\r\n\t ]+/', ' ', $str);$str = preg_replace('/[\#\"\*\/\:\<\>\?\'\|\,]+/', ' ', $str);$str = strtolower($str);$str = html_entity_decode($str, ENT_QUOTES, "utf-8");$str = htmlentities($str, ENT_QUOTES, "utf-8");$str = preg_replace("/(&)([a-z])([a-z]+;)/i", '$2', $str);$str = str_replace(' ', '-', $str);$str = rawurlencode($str);$str = str_replace('%', '-', $str);$str = str_replace(['-----','----','---','--'], '-', $str);return trim(strtolower($str));}}