X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FPhoto.php;h=8ba01e33655d280ede203d5f774e3c6b51465a42;hb=48087136680d345e9222c974ae983262b319d308;hp=fe416c360f54e55d1c19c16e99867dd4a65e9ebf;hpb=2f06d271bb4380cacd95d9f17ecf65dfc7faffcb;p=friendica.git diff --git a/src/Model/Photo.php b/src/Model/Photo.php index fe416c360f..8ba01e3365 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -1,6 +1,6 @@ getByName($photo['backend-class'] ?? ''); - if (empty($backendClass)) { - // legacy data storage in "data" column - $i = self::selectFirst(['data'], ['id' => $photo['id']]); - if ($i === false) { - return null; + try { + $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? ''); + /// @todo refactoring this returning, because the storage returns a "string" which is casted in different ways - a check "instanceof Image" will fail! + return $backendClass->get($photo['backend-ref'] ?? ''); + } catch (InvalidClassStorageException $storageException) { + try { + // legacy data storage in "data" column + $i = self::selectFirst(['data'], ['id' => $photo['id']]); + if ($i !== false) { + return $i['data']; + } else { + DI::logger()->info('Stored legacy data is empty', ['photo' => $photo]); + } + } catch (\Exception $exception) { + DI::logger()->info('Unexpected database exception', ['photo' => $photo, 'exception' => $exception]); } - $data = $i['data']; - } else { - $backendRef = $photo['backend-ref'] ?? ''; - $data = $backendClass->get($backendRef); + } catch (ReferenceStorageException $referenceStorageException) { + DI::logger()->debug('Invalid reference for photo', ['photo' => $photo, 'exception' => $referenceStorageException]); + } catch (StorageException $storageException) { + DI::logger()->info('Unexpected storage exception', ['photo' => $photo, 'exception' => $storageException]); + } catch (\ImagickException $imagickException) { + DI::logger()->info('Unexpected imagick exception', ['photo' => $photo, 'exception' => $imagickException]); } - return $data; + + return null; } /** @@ -217,14 +236,9 @@ class Photo * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getImageForPhoto(array $photo) + public static function getImageForPhoto(array $photo): Image { - $data = self::getImageDataForPhoto($photo); - if (empty($data)) { - return null; - } - - return new Image($data, $photo['type']); + return new Image(self::getImageDataForPhoto($photo), $photo['type']); } /** @@ -245,13 +259,17 @@ class Photo * Construct a photo array for a system resource image * * @param string $filename Image file name relative to code root - * @param string $mimetype Image mime type. Defaults to "image/jpeg" + * @param string $mimetype Image mime type. Is guessed by file name when empty. * * @return array * @throws \Exception */ - public static function createPhotoForSystemResource($filename, $mimetype = "image/jpeg") + public static function createPhotoForSystemResource($filename, $mimetype = '') { + if (empty($mimetype)) { + $mimetype = Images::guessTypeByExtension($filename); + } + $fields = self::getFields(); $values = array_fill(0, count($fields), ""); @@ -269,13 +287,17 @@ class Photo * * @param string $url Image URL * @param int $uid User ID of the requesting person - * @param string $mimetype Image mime type. Defaults to "image/jpeg" + * @param string $mimetype Image mime type. Is guessed by file name when empty. * * @return array * @throws \Exception */ - public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = "image/jpeg") + public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = '') { + if (empty($mimetype)) { + $mimetype = Images::guessTypeByExtension($url); + } + $fields = self::getFields(); $values = array_fill(0, count($fields), ""); @@ -308,7 +330,7 @@ class Photo * @return boolean True on success * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function store(Image $Image, $uid, $cid, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = "", $allow_gid = "", $deny_cid = "", $deny_gid = "", $desc = "") + public static function store(Image $Image, $uid, $cid, $rid, $filename, $album, $scale, $type = self::DEFAULT, $allow_cid = "", $allow_gid = "", $deny_cid = "", $deny_gid = "", $desc = "") { $photo = self::selectFirst(["guid"], ["`resource-id` = ? AND `guid` != ?", $rid, ""]); if (DBA::isResult($photo)) { @@ -326,20 +348,20 @@ class Photo // Get defined storage backend. // if no storage backend, we use old "data" column in photo table. // if is an existing photo, reuse same backend - $data = ""; + $data = ""; $backend_ref = ""; + $storage = ""; - if (DBA::isResult($existing_photo)) { - $backend_ref = (string)$existing_photo["backend-ref"]; - $storage = DI::storageManager()->getByName($existing_photo["backend-class"] ?? ''); - } else { - $storage = DI::storage(); - } - - if (empty($storage)) { - $data = $Image->asString(); - } else { + try { + if (DBA::isResult($existing_photo)) { + $backend_ref = (string)$existing_photo["backend-ref"]; + $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? ''); + } else { + $storage = DI::storage(); + } $backend_ref = $storage->put($Image->asString(), $backend_ref); + } catch (InvalidClassStorageException $storageException) { + $data = $Image->asString(); } $fields = [ @@ -358,7 +380,8 @@ class Photo "datasize" => strlen($Image->asString()), "data" => $data, "scale" => $scale, - "profile" => $profile, + "photo-type" => $type, + "profile" => false, "allow_cid" => $allow_cid, "allow_gid" => $allow_gid, "deny_cid" => $deny_cid, @@ -395,12 +418,15 @@ class Photo $photos = DBA::select('photo', ['id', 'backend-class', 'backend-ref'], $conditions); while ($photo = DBA::fetch($photos)) { - $backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - if (!empty($backend_class)) { - if ($backend_class->delete($photo["backend-ref"] ?? '')) { - // Delete the photos after they had been deleted successfully - DBA::delete("photo", ['id' => $photo['id']]); - } + try { + $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); + $backend_class->delete($photo['backend-ref'] ?? ''); + // Delete the photos after they had been deleted successfully + DBA::delete("photo", ['id' => $photo['id']]); + } catch (InvalidClassStorageException $storageException) { + DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]); + } catch (ReferenceStorageException $referenceStorageException) { + DI::logger()->debug('Photo doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]); } } @@ -429,10 +455,10 @@ class Photo $photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions); foreach($photos as $photo) { - $backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - if (!empty($backend_class)) { + try { + $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); $fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']); - } else { + } catch (InvalidClassStorageException $storageException) { $fields["data"] = $img->asString(); } } @@ -459,7 +485,7 @@ class Photo $micro = ""; $photo = DBA::selectFirst( - "photo", ["resource-id"], ["uid" => $uid, "contact-id" => $cid, "scale" => 4, "album" => self::CONTACT_PHOTOS] + "photo", ["resource-id"], ["uid" => $uid, "contact-id" => $cid, "scale" => 4, "photo-type" => self::CONTACT_AVATAR] ); if (!empty($photo['resource-id'])) { $resource_id = $photo["resource-id"]; @@ -471,11 +497,12 @@ class Photo $filename = basename($image_url); if (!empty($image_url)) { - $ret = DI::httpRequest()->get($image_url); + $ret = DI::httpClient()->get($image_url); $img_str = $ret->getBody(); $type = $ret->getContentType(); } else { $img_str = ''; + $type = ''; } if ($quit_on_error && ($img_str == "")) { @@ -511,7 +538,7 @@ class Photo Logger::info('Avatar is resized', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'type' => $Image->getType()]); } - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 4); + $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 4, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; @@ -519,7 +546,7 @@ class Photo $Image->scaleDown(80); - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 5); + $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 5, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; @@ -527,7 +554,7 @@ class Photo $Image->scaleDown(48); - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 6); + $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 6, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; @@ -538,25 +565,6 @@ class Photo $image_url = DI::baseUrl() . "/photo/" . $resource_id . "-4." . $Image->getExt() . $suffix; $thumb = DI::baseUrl() . "/photo/" . $resource_id . "-5." . $Image->getExt() . $suffix; $micro = DI::baseUrl() . "/photo/" . $resource_id . "-6." . $Image->getExt() . $suffix; - - // Remove the cached photo - $a = DI::app(); - $basepath = $a->getBasePath(); - - if (is_dir($basepath . "/photo")) { - $filename = $basepath . "/photo/" . $resource_id . "-4." . $Image->getExt(); - if (file_exists($filename)) { - unlink($filename); - } - $filename = $basepath . "/photo/" . $resource_id . "-5." . $Image->getExt(); - if (file_exists($filename)) { - unlink($filename); - } - $filename = $basepath . "/photo/" . $resource_id . "-6." . $Image->getExt(); - if (file_exists($filename)) { - unlink($filename); - } - } } else { $photo_failure = true; } @@ -625,29 +633,34 @@ class Photo { $sql_extra = Security::getPermissionsSQLByUserId($uid); + $avatar_type = (local_user() && (local_user() == $uid)) ? self::USER_AVATAR : self::DEFAULT; + $banner_type = (local_user() && (local_user() == $uid)) ? self::USER_BANNER : self::DEFAULT; + $key = "photo_albums:".$uid.":".local_user().":".remote_user(); $albums = DI::cache()->get($key); if (is_null($albums) || $update) { if (!DI::config()->get("system", "no_count", false)) { /// @todo This query needs to be renewed. It is really slow // At this time we just store the data in the cache - $albums = q("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`, ANY_VALUE(`created`) AS `created` + $albums = DBA::toArray(DBA::p("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`, ANY_VALUE(`created`) AS `created` FROM `photo` - WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' $sql_extra + WHERE `uid` = ? AND `photo-type` IN (?, ?, ?) $sql_extra GROUP BY `album` ORDER BY `created` DESC", - intval($uid), - DBA::escape(self::CONTACT_PHOTOS), - DBA::escape(DI::l10n()->t(self::CONTACT_PHOTOS)) - ); + $uid, + self::DEFAULT, + $banner_type, + $avatar_type + )); } else { // This query doesn't do the count and is much faster - $albums = q("SELECT DISTINCT(`album`), '' AS `total` + $albums = DBA::toArray(DBA::p("SELECT DISTINCT(`album`), '' AS `total` FROM `photo` USE INDEX (`uid_album_scale_created`) - WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' $sql_extra", - intval($uid), - DBA::escape(self::CONTACT_PHOTOS), - DBA::escape(DI::l10n()->t(self::CONTACT_PHOTOS)) - ); + WHERE `uid` = ? AND `photo-type` IN (?, ?, ?) $sql_extra", + $uid, + self::DEFAULT, + $banner_type, + $avatar_type + )); } DI::cache()->set($key, $albums, Duration::DAY); } @@ -733,7 +746,7 @@ class Photo 'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', 'resource-id' => $image_rid, 'uid' => $uid ]; - if (!Photo::exists($condition)) { + if (!self::exists($condition)) { $photo = self::selectFirst(['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'uid'], ['resource-id' => $image_rid]); if (!DBA::isResult($photo)) { Logger::info('Image not found', ['resource-id' => $image_rid]); @@ -759,7 +772,7 @@ class Photo /** * Add permissions to photo ressource * @todo mix with previous photo permissions - * + * * @param string $image_rid * @param integer $uid * @param string $str_contact_allow @@ -776,50 +789,37 @@ class Photo $condition = ['resource-id' => $image_rid, 'uid' => $uid]; Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]); - Photo::update($fields, $condition); + self::update($fields, $condition); } /** - * Strips known picture extensions from picture links + * Fetch the guid and scale from picture links * * @param string $name Picture link - * @return string stripped picture link - * @throws \Exception - */ - public static function stripExtension($name) - { - $name = str_replace([".jpg", ".png", ".gif"], ["", "", ""], $name); - foreach (Images::supportedTypes() as $m => $e) { - $name = str_replace("." . $e, "", $name); - } - return $name; - } - - /** - * Returns the GUID from picture links - * - * @param string $name Picture link - * @return string GUID - * @throws \Exception + * @return array */ - public static function getGUID($name) + public static function getResourceData(string $name):array { $base = DI::baseUrl()->get(); $guid = str_replace([Strings::normaliseLink($base), '/photo/'], '', Strings::normaliseLink($name)); - $guid = self::stripExtension($guid); + if (parse_url($guid, PHP_URL_SCHEME)) { + return []; + } + + $guid = pathinfo($guid, PATHINFO_FILENAME); if (substr($guid, -2, 1) != "-") { - return ''; + return []; } $scale = intval(substr($guid, -1, 1)); if (!is_numeric($scale)) { - return ''; + return []; } $guid = substr($guid, 0, -2); - return $guid; + return ['guid' => $guid, 'scale' => $scale]; } /** @@ -831,13 +831,27 @@ class Photo */ public static function isLocal($name) { - $guid = self::getGUID($name); + return (bool)self::getIdForName($name); + } - if (empty($guid)) { - return false; + /** + * Return the id of a local photo + * + * @param string $name Picture link + * @return int + */ + public static function getIdForName($name) + { + $data = self::getResourceData($name); + if (empty($data)) { + return 0; } - return DBA::exists('photo', ['resource-id' => $guid]); + $photo = DBA::selectFirst('photo', ['id'], ['resource-id' => $data['guid'], 'scale' => $data['scale']]); + if (!empty($photo['id'])) { + return $photo['id']; + } + return 0; } /** @@ -860,22 +874,73 @@ class Photo return DBA::exists('photo', ['resource-id' => $guid]); } - /** - * - * @param int $uid User ID - * @param array $files uploaded file array - * @return array photo record - */ - public static function upload(int $uid, array $files) + private static function fitImageSize($Image) { - Logger::info('starting new upload'); + $max_length = DI::config()->get('system', 'max_image_length'); + if ($max_length > 0) { + $Image->scaleDown($max_length); + Logger::info('File upload: Scaling picture to new size', ['max-length' => $max_length]); + } - $user = User::getOwnerDataById($uid); - if (empty($user)) { - Logger::notice('User not found', ['uid' => $uid]); + $filesize = strlen($Image->asString()); + $width = $Image->getWidth(); + $height = $Image->getHeight(); + + $maximagesize = DI::config()->get('system', 'maximagesize'); + + if (!empty($maximagesize) && ($filesize > $maximagesize)) { + // Scale down to multiples of 640 until the maximum size isn't exceeded anymore + foreach ([5120, 2560, 1280, 640] as $pixels) { + if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) { + Logger::info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); + $Image->scaleDown($pixels); + $filesize = strlen($Image->asString()); + $width = $Image->getWidth(); + $height = $Image->getHeight(); + } + } + if ($filesize > $maximagesize) { + Logger::notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); + return null; + } + } + + return $Image; + } + + private static function loadImageFromURL(string $image_url) + { + $filename = basename($image_url); + if (!empty($image_url)) { + $ret = DI::httpClient()->get($image_url); + $img_str = $ret->getBody(); + $type = $ret->getContentType(); + } else { + $img_str = ''; + $type = ''; + } + + if (empty($img_str)) { + Logger::notice('Empty content'); return []; } + $type = Images::getMimeTypeByData($img_str, $image_url, $type); + + $Image = new Image($img_str, $type); + + $Image = self::fitImageSize($Image); + if (empty($Image)) { + return []; + } + + return ['image' => $Image, 'filename' => $filename]; + } + + private static function uploadImage(array $files) + { + Logger::info('starting new upload'); + if (empty($files)) { Logger::notice('Empty upload file'); return []; @@ -922,7 +987,7 @@ class Photo } if (empty($src)) { - Logger::notice('No source file name', ['uid' => $uid, 'files' => $files]); + Logger::notice('No source file name', ['files' => $files]); return []; } @@ -933,53 +998,64 @@ class Photo $imagedata = @file_get_contents($src); $Image = new Image($imagedata, $filetype); if (!$Image->isValid()) { - Logger::notice('Image is unvalid', ['uid' => $uid, 'files' => $files]); + Logger::notice('Image is unvalid', ['files' => $files]); return []; } $Image->orient($src); @unlink($src); - $max_length = DI::config()->get('system', 'max_image_length'); - if (!$max_length) { - $max_length = MAX_IMAGE_LENGTH; - } - if ($max_length > 0) { - $Image->scaleDown($max_length); - $filesize = strlen($Image->asString()); - Logger::info('File upload: Scaling picture to new size', ['max-length' => $max_length]); + $Image = self::fitImageSize($Image); + if (empty($Image)) { + return []; } - $width = $Image->getWidth(); - $height = $Image->getHeight(); + return ['image' => $Image, 'filename' => $filename]; + } - $maximagesize = DI::config()->get('system', 'maximagesize'); + /** + * @param int $uid User ID + * @param array $files uploaded file array + * @param string $album + * @param string|null $allow_cid + * @param string|null $allow_gid + * @param string $deny_cid + * @param string $deny_gid + * @param string $desc + * @param string $resource_id + * @return array photo record + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + public static function upload(int $uid, array $files, string $album = '', string $allow_cid = null, string $allow_gid = null, string $deny_cid = '', string $deny_gid = '', string $desc = '', string $resource_id = ''): array + { + $user = User::getOwnerDataById($uid); + if (empty($user)) { + Logger::notice('User not found', ['uid' => $uid]); + return []; + } - if (!empty($maximagesize) && ($filesize > $maximagesize)) { - // Scale down to multiples of 640 until the maximum size isn't exceeded anymore - foreach ([5120, 2560, 1280, 640] as $pixels) { - if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) { - Logger::info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); - $Image->scaleDown($pixels); - $filesize = strlen($Image->asString()); - $width = $Image->getWidth(); - $height = $Image->getHeight(); - } - } - if ($filesize > $maximagesize) { - @unlink($src); - Logger::notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); - return []; - } + $data = self::uploadImage($files); + if (empty($data)) { + Logger::info('upload failed'); + return []; } - $resource_id = Photo::newResource(); - $album = DI::l10n()->t('Wall Photos'); - $defperm = '<' . $user['id'] . '>'; + $Image = $data['image']; + $filename = $data['filename']; + $width = $Image->getWidth(); + $height = $Image->getHeight(); + + $resource_id = $resource_id ?: self::newResource(); + $album = $album ?: DI::l10n()->t('Wall Photos'); + + if (is_null($allow_cid) && is_null($allow_gid)) { + $allow_cid = '<' . $user['id'] . '>'; + $allow_gid = ''; + } $smallest = 0; - $r = Photo::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 0, 0, $defperm); + $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 0, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if (!$r) { Logger::notice('Photo could not be stored'); return []; @@ -987,7 +1063,7 @@ class Photo if ($width > 640 || $height > 640) { $Image->scaleDown(640); - $r = Photo::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 1, 0, $defperm); + $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 1, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if ($r) { $smallest = 1; } @@ -995,7 +1071,7 @@ class Photo if ($width > 320 || $height > 320) { $Image->scaleDown(320); - $r = Photo::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 2, 0, $defperm); + $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 2, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if ($r && ($smallest == 0)) { $smallest = 2; } @@ -1010,16 +1086,152 @@ class Photo $picture = []; - $picture['id'] = $photo['id']; - $picture['size'] = $photo['datasize']; - $picture['width'] = $photo['width']; - $picture['height'] = $photo['height']; - $picture['type'] = $photo['type']; - $picture['albumpage'] = DI::baseUrl() . '/photos/' . $user['nickname'] . '/image/' . $resource_id; - $picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $Image->getExt(); - $picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $Image->getExt(); + $picture['id'] = $photo['id']; + $picture['resource_id'] = $resource_id; + $picture['size'] = $photo['datasize']; + $picture['width'] = $photo['width']; + $picture['height'] = $photo['height']; + $picture['type'] = $photo['type']; + $picture['albumpage'] = DI::baseUrl() . '/photos/' . $user['nickname'] . '/image/' . $resource_id; + $picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $Image->getExt(); + $picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $Image->getExt(); Logger::info('upload done', ['picture' => $picture]); return $picture; } + + /** + * Upload a user avatar + * + * @param int $uid User ID + * @param array $files uploaded file array + * @param string $url External image url + * @return string avatar resource + */ + public static function uploadAvatar(int $uid, array $files, string $url = ''): string + { + if (!empty($files)) { + $data = self::uploadImage($files); + if (empty($data)) { + Logger::info('upload failed'); + return ''; + } + } elseif (!empty($url)) { + $data = self::loadImageFromURL($url); + if (empty($data)) { + Logger::info('loading from external url failed'); + return ''; + } + } else { + Logger::info('Neither files nor url provided'); + return ''; + } + + $Image = $data['image']; + $filename = $data['filename']; + $width = $Image->getWidth(); + $height = $Image->getHeight(); + + $resource_id = self::newResource(); + $album = DI::l10n()->t(self::PROFILE_PHOTOS); + + // upload profile image (scales 4, 5, 6) + logger::info('starting new profile image upload'); + + if ($width > 300 || $height > 300) { + $Image->scaleDown(300); + } + + $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 4, self::USER_AVATAR); + if (!$r) { + logger::notice('profile image upload with scale 4 (300) failed'); + } + + if ($width > 80 || $height > 80) { + $Image->scaleDown(80); + } + + $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 5, self::USER_AVATAR); + if (!$r) { + logger::notice('profile image upload with scale 5 (80) failed'); + } + + if ($width > 48 || $height > 48) { + $Image->scaleDown(48); + } + + $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 6, self::USER_AVATAR); + if (!$r) { + logger::notice('profile image upload with scale 6 (48) failed'); + } + + logger::info('new profile image upload ended'); + + $condition = ["`profile` AND `resource-id` != ? AND `uid` = ?", $resource_id, $uid]; + self::update(['profile' => false, 'photo-type' => self::DEFAULT], $condition); + + Contact::updateSelfFromUserID($uid, true); + + // Update global directory in background + Profile::publishUpdate($uid); + + return $resource_id; + } + + /** + * Upload a user banner + * + * @param int $uid User ID + * @param array $files uploaded file array + * @param string $url External image url + * @return string avatar resource + */ + public static function uploadBanner(int $uid, array $files = [], string $url = ''): string + { + if (!empty($files)) { + $data = self::uploadImage($files); + if (empty($data)) { + Logger::info('upload failed'); + return ''; + } + } elseif (!empty($url)) { + $data = self::loadImageFromURL($url); + if (empty($data)) { + Logger::info('loading from external url failed'); + return ''; + } + } else { + Logger::info('Neither files nor url provided'); + return ''; + } + + $Image = $data['image']; + $filename = $data['filename']; + $width = $Image->getWidth(); + $height = $Image->getHeight(); + + $resource_id = self::newResource(); + $album = DI::l10n()->t(self::BANNER_PHOTOS); + + if ($width > 960) { + $Image->scaleDown(960); + } + + $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 3, self::USER_BANNER); + if (!$r) { + logger::notice('profile banner upload with scale 3 (960) failed'); + } + + logger::info('new profile banner upload ended'); + + $condition = ["`photo-type` = ? AND `resource-id` != ? AND `uid` = ?", self::USER_BANNER, $resource_id, $uid]; + self::update(['photo-type' => self::DEFAULT], $condition); + + Contact::updateSelfFromUserID($uid, true); + + // Update global directory in background + Profile::publishUpdate($uid); + + return $resource_id; + } }