X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FPhoto.php;h=bedc216fb20ab827d61568385c0e5e1721e38cf2;hb=fa14a02a192efdd061e5184585395a46968855e7;hp=44be9a31a277cf36e41547583f41bcf6857d7eee;hpb=b84c68f02455ea6d2a4384229535c45d6426fe4b;p=friendica.git diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 44be9a31a2..bedc216fb2 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -1,6 +1,6 @@ parameters['type'])) { + if (!empty($this->parameters['customsize'])) { + $customsize = intval($this->parameters['customsize']); + $square_resize = !in_array($this->parameters['type'], ['media', 'preview']); + } + + if (!empty($this->parameters['guid'])) { + $guid = $this->parameters['guid']; + $account = DBA::selectFirst('account-user-view', ['id'], ['guid' => $guid], ['order' => ['uid' => true]]); + if (empty($account)) { + throw new HTTPException\NotFoundException(); + } + + $id = $account['id']; + } + + // Contact Id Fallback, to remove after version 2021.12 + if (isset($this->parameters['contact_id'])) { + $id = intval($this->parameters['contact_id']); + } + + if (!empty($this->parameters['nickname_ext'])) { + $nickname = pathinfo($this->parameters['nickname_ext'], PATHINFO_FILENAME); + $user = User::getByNickname($nickname, ['uid']); + if (empty($user)) { + throw new HTTPException\NotFoundException(); + } + + $id = $user['uid']; + } + + // User Id Fallback, to remove after version 2021.12 + if (!empty($this->parameters['uid_ext'])) { + $id = intval(pathinfo($this->parameters['uid_ext'], PATHINFO_FILENAME)); + } + + // Please refactor this for the love of everything that's good + if (isset($this->parameters['id'])) { + $id = $this->parameters['id']; + } + + if (empty($id)) { + Logger::notice('No picture id was detected', ['parameters' => $this->parameters, 'query' => DI::args()->getQueryString()]); + throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo is not available.')); + } + + $photo = self::getPhotoById($id, $this->parameters['type'], $customsize ?: Proxy::PIXEL_SMALL); + } else { + $photoid = pathinfo($this->parameters['name'], PATHINFO_FILENAME); $scale = 0; if (substr($photoid, -2, 1) == "-") { $scale = intval(substr($photoid, -1, 1)); @@ -91,21 +138,24 @@ class Photo extends BaseModule } $photo = MPhoto::getPhoto($photoid, $scale); if ($photo === false) { - throw new \Friendica\Network\HTTPException\NotFoundException(DI::l10n()->t('The Photo with id %s is not available.', $photoid)); + throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo with id %s is not available.', $photoid)); } - } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); } + $fetch = microtime(true) - $stamp; if ($photo === false) { - throw new \Friendica\Network\HTTPException\NotFoundException(); + throw new HTTPException\NotFoundException(); } $cacheable = ($photo["allow_cid"] . $photo["allow_gid"] . $photo["deny_cid"] . $photo["deny_gid"] === "") && (isset($photo["cacheable"]) ? $photo["cacheable"] : true); $stamp = microtime(true); + $imgdata = MPhoto::getImageDataForPhoto($photo); + if (empty($imgdata)) { + throw new HTTPException\NotFoundException(); + } // The mimetype for an external or system resource can only be known reliably after it had been fetched if (in_array($photo['backend-class'], [ExternalResource::NAME, SystemResource::NAME])) { @@ -118,8 +168,14 @@ class Photo extends BaseModule $data = microtime(true) - $stamp; if (empty($imgdata)) { - Logger::warning("Invalid photo with id {$photo["id"]}."); - throw new \Friendica\Network\HTTPException\InternalServerErrorException(DI::l10n()->t('Invalid photo with id %s.', $photo["id"])); + Logger::warning('Invalid photo', ['id' => $photo['id']]); + if (in_array($photo['backend-class'], [ExternalResource::NAME])) { + $reference = json_decode($photo['backend-ref'], true); + $error = DI::l10n()->t('Invalid external resource with url %s.', $reference['url']); + } else { + $error = DI::l10n()->t('Invalid photo with id %s.', $photo['id']); + } + throw new HTTPException\InternalServerErrorException($error); } // if customsize is set and image is not a gif, resize it @@ -169,14 +225,22 @@ class Photo extends BaseModule 'output' => number_format($output, 3), 'rest' => number_format($rest, 3)]); } - exit(); + System::exit(); } - private static function getAvatar($uid, $type="avatar", $customsize) + /** + * Fetches photo record by given id number, type and custom size + * + * @param int $id Photo id + * @param string $type Photo type + * @param int $customsize Custom size (?) + * @return array|bool Array on success, false on error + */ + private static function getPhotoById(int $id, string $type, int $customsize) { switch($type) { - case "preview": - $media = DBA::selectFirst('post-media', ['preview', 'url', 'type', 'uri-id'], ['id' => $uid]); + case 'preview': + $media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $id]); if (empty($media)) { return false; } @@ -193,10 +257,10 @@ class Photo extends BaseModule if (Network::isLocalLink($url) && preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $url, $matches)) { return MPhoto::getPhoto($matches[1], $matches[2]); } - - return MPhoto::createPhotoForExternalResource($url, (int)local_user()); - case "media": - $media = DBA::selectFirst('post-media', ['url', 'uri-id'], ['id' => $uid, 'type' => Post\Media::IMAGE]); + + return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype']); + case 'media': + $media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $id, 'type' => Post\Media::IMAGE]); if (empty($media)) { return false; } @@ -205,15 +269,43 @@ class Photo extends BaseModule return MPhoto::getPhoto($matches[1], $matches[2]); } - return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user()); - case "contact": - $contact = Contact::getById($uid, ['uid', 'url', 'avatar', 'photo', 'xmpp', 'addr']); + return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user(), $media['mimetype']); + case 'link': + $link = DBA::selectFirst('post-link', ['url', 'mimetype'], ['id' => $id]); + if (empty($link)) { + return false; + } + + return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype']); + case 'contact': + $fields = ['uid', 'uri-id', 'url', 'nurl', 'avatar', 'photo', 'xmpp', 'addr', 'network', 'failed', 'updated']; + $contact = Contact::getById($id, $fields); if (empty($contact)) { return false; } - If (($contact['uid'] != 0) && empty($contact['photo']) && empty($contact['avatar'])) { - $contact = Contact::getByURL($contact['url'], false, ['avatar', 'photo', 'xmpp', 'addr']); + + // For local users directly use the photo record that is marked as the profile + if (Network::isLocalLink($contact['url'])) { + $contact = Contact::selectFirst($fields, ['nurl' => $contact['nurl'], 'self' => true]); + if (!empty($contact)) { + if ($customsize <= Proxy::PIXEL_MICRO) { + $scale = 6; + } elseif ($customsize <= Proxy::PIXEL_THUMB) { + $scale = 5; + } else { + $scale = 4; + } + $photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $contact['uid'], 'profile' => 1]); + if (!empty($photo)) { + return $photo; + } + } } + + if (!empty($contact['uid']) && empty($contact['photo']) && empty($contact['avatar'])) { + $contact = Contact::getByURL($contact['url'], false, $fields); + } + if (!empty($contact['photo']) && !empty($contact['avatar'])) { // Fetch photo directly $resourceid = MPhoto::ridFromURI($contact['photo']); @@ -221,59 +313,99 @@ class Photo extends BaseModule $photo = MPhoto::selectFirst([], ['resource-id' => $resourceid], ['order' => ['scale']]); if (!empty($photo)) { return $photo; + } else { + $url = $contact['avatar']; } + } else { + $url = $contact['photo']; } - // We continue with the avatar link when the photo link is invalid - $url = $contact['avatar']; } elseif (!empty($contact['avatar'])) { $url = $contact['avatar']; - } elseif ($customsize <= Proxy::PIXEL_MICRO) { - $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO); - } elseif ($customsize <= Proxy::PIXEL_THUMB) { - $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB); - } else { - $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL); } - return MPhoto::createPhotoForExternalResource($url); - case "header": - $contact = Contact::getById($uid, ['uid', 'url', 'header']); + $mimetext = ''; + if (!empty($url)) { + $mime = ParseUrl::getContentType($url, HttpClientAccept::IMAGE); + if (!empty($mime)) { + $mimetext = $mime[0] . '/' . $mime[1]; + } else { + // Only update federated accounts that hadn't failed before and hadn't been updated recently + $update = in_array($contact['network'], Protocol::FEDERATED) && !$contact['failed'] + && ((time() - strtotime($contact['updated']) > 86400)); + if ($update) { + $curlResult = DI::httpClient()->head($url, [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::IMAGE]); + $update = !$curlResult->isSuccess() && ($curlResult->getReturnCode() == 404); + Logger::debug('Got return code for avatar', ['return code' => $curlResult->getReturnCode(), 'cid' => $id, 'url' => $contact['url'], 'avatar' => $url]); + } + if ($update) { + Logger::info('Invalid file, contact update initiated', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]); + Worker::add(PRIORITY_LOW, 'UpdateContact', $id); + } else { + Logger::info('Invalid file', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]); + } + } + if (!empty($mimetext) && ($mime[0] != 'image') && ($mimetext != 'application/octet-stream')) { + Logger::info('Unexpected Content-Type', ['mime' => $mimetext, 'url' => $url]); + $mimetext = ''; + } if (!empty($mimetext)) { + Logger::debug('Expected Content-Type', ['mime' => $mimetext, 'url' => $url]); + } + } + if (empty($mimetext)) { + if ($customsize <= Proxy::PIXEL_MICRO) { + $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO); + } elseif ($customsize <= Proxy::PIXEL_THUMB) { + $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB); + } else { + $url = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL); + } + } + return MPhoto::createPhotoForExternalResource($url, 0, $mimetext); + case 'header': + $fields = ['uid', 'url', 'header', 'network', 'gsid']; + $contact = Contact::getById($id, $fields); if (empty($contact)) { return false; } If (($contact['uid'] != 0) && empty($contact['header'])) { - $contact = Contact::getByURL($contact['url'], false, ['header']); + $contact = Contact::getByURL($contact['url'], false, $fields); } if (!empty($contact['header'])) { $url = $contact['header']; } else { - $url = DI::baseUrl() . '/images/blank.png'; + $url = Contact::getDefaultHeader($contact); } return MPhoto::createPhotoForExternalResource($url); - case "profile": - case "custom": + case 'banner': + $photo = MPhoto::selectFirst([], ['scale' => 3, 'uid' => $id, 'photo-type' => MPhoto::USER_BANNER]); + if (!empty($photo)) { + return $photo; + } + return MPhoto::createPhotoForExternalResource(DI::baseUrl() . '/images/friendica-banner.jpg'); + case 'profile': + case 'custom': $scale = 4; break; - case "micro": + case 'micro': $scale = 6; break; - case "avatar": + case 'avatar': default: $scale = 5; } - $photo = MPhoto::selectFirst([], ["scale" => $scale, "uid" => $uid, "profile" => 1]); + $photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $id, 'profile' => 1]); if (empty($photo)) { - $contact = DBA::selectFirst('contact', [], ['uid' => $uid, 'self' => true]) ?: []; + $contact = DBA::selectFirst('contact', [], ['uid' => $id, 'self' => true]) ?: []; switch($type) { - case "profile": - case "custom": + case 'profile': + case 'custom': $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL); break; - case "micro": + case 'micro': $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO); break; - case "avatar": + case 'avatar': default: $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB); }