X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FPhoto.php;h=a92568015ca72042361bb64425f90ba330feb578;hb=35e2ae39252f6713a09c80026eeacf184f68437a;hp=64d9e3542ae0f29836745dd0e9c389646a167892;hpb=c281589fe2eb7d27ac25413244a5d0e4a1c1ccd5;p=friendica.git diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 64d9e3542a..a92568015c 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -1,6 +1,6 @@ argc <= 1 || $a->argc > 4) { - throw new \Friendica\Network\HTTPException\BadRequestException(); - } if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - header("HTTP/1.1 304 Not Modified"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); @@ -63,59 +67,121 @@ class Photo extends BaseModule header_remove("Expires"); header_remove("Cache-Control"); } - exit; + throw new NotModifiedException(); } + Profile::addVisitorCookieForHTTPSigner(); + $customsize = 0; - $photo = false; + $square_resize = true; $scale = null; - // @TODO: Replace with parameter from router $stamp = microtime(true); - switch($a->argc) { - case 4: - $customsize = intval($a->argv[2]); - $uid = MPhoto::stripExtension($a->argv[3]); - $photo = self::getAvatar($uid, $a->argv[1]); - break; - case 3: - $uid = MPhoto::stripExtension($a->argv[2]); - $photo = self::getAvatar($uid, $a->argv[1]); - break; - case 2: - $photoid = MPhoto::stripExtension($a->argv[1]); - $scale = 0; - if (substr($photoid, -2, 1) == "-") { - $scale = intval(substr($photoid, -1, 1)); - $photoid = substr($photoid, 0, -2); + // User avatar + if (!empty($this->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(); } - $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)); + + $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(); } - break; + + $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)); + $photoid = substr($photoid, 0, -2); + } + $photo = MPhoto::getPhoto($photoid, $scale); + if ($photo === false) { + throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo with id %s is not available.', $photoid)); + } } + $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])) { + $mimetype = Images::getMimeTypeByData($imgdata); + if (!empty($mimetype)) { + $photo['type'] = $mimetype; + } + } + $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 - if ($photo['type'] !== "image/gif" && $customsize > 0 && $customsize < 501) { + if ($photo['type'] !== "image/gif" && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) { $img = new Image($imgdata, $photo['type']); $img->scaleToSquare($customsize); $imgdata = $img->asString(); + } elseif ($photo['type'] !== "image/gif" && $customsize > 0) { + $img = new Image($imgdata, $photo['type']); + $img->scaleDown($customsize); + $imgdata = $img->asString(); } if (function_exists("header_remove")) { @@ -157,9 +223,106 @@ class Photo extends BaseModule exit(); } - private static function getAvatar($uid, $type="avatar") + private static function getPhotoByid(int $id, $type, $customsize) { switch($type) { + case "preview": + $media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $id]); + if (empty($media)) { + return false; + } + $url = $media['preview']; + + if (empty($url) && ($media['type'] == Post\Media::IMAGE)) { + $url = $media['url']; + } + + if (empty($url)) { + return false; + } + + 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(), $media['mimetype']); + case "media": + $media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $id, 'type' => Post\Media::IMAGE]); + if (empty($media)) { + return false; + } + + if (Network::isLocalLink($media['url']) && preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['url'], $matches)) { + return MPhoto::getPhoto($matches[1], $matches[2]); + } + + 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": + $contact = Contact::getById($id, ['uid', 'url', 'avatar', 'photo', 'xmpp', 'addr']); + 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']); + } + if (!empty($contact['photo']) && !empty($contact['avatar'])) { + // Fetch photo directly + $resourceid = MPhoto::ridFromURI($contact['photo']); + if (!empty($resourceid)) { + $photo = MPhoto::selectFirst([], ['resource-id' => $resourceid], ['order' => ['scale']]); + if (!empty($photo)) { + return $photo; + } + } + // We continue with the avatar link when the photo link is invalid + $url = $contact['avatar']; + } elseif (!empty($contact['avatar'])) { + $url = $contact['avatar']; + } + $mimetext = ''; + if (!empty($url)) { + $mime = ParseUrl::getContentType($url); + if (!empty($mime)) { + $mimetext = $mime[0] . '/' . $mime[1]; + } else { + Logger::info('Invalid file', ['url' => $url]); + } + if (!empty($mimetext) && ($mime[0] != 'image') && ($mimetext != 'application/octet-stream')) { + Logger::info('Unexpected Content-Type', ['mime' => $mimetext, 'url' => $url]); + $mimetext = ''; + } + } + 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": + $contact = Contact::getById($id, ['uid', 'url', 'header']); + if (empty($contact)) { + return false; + } + If (($contact['uid'] != 0) && empty($contact['header'])) { + $contact = Contact::getByURL($contact['url'], false, ['header']); + } + if (!empty($contact['header'])) { + $url = $contact['header']; + } else { + $url = DI::baseUrl() . '/images/blank.png'; + } + return MPhoto::createPhotoForExternalResource($url); case "profile": case "custom": $scale = 4; @@ -172,9 +335,9 @@ class Photo extends BaseModule $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": @@ -188,8 +351,13 @@ class Photo extends BaseModule default: $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB); } - - $photo = MPhoto::createPhotoForSystemResource($default); + + $parts = parse_url($default); + if (!empty($parts['scheme']) || !empty($parts['host'])) { + $photo = MPhoto::createPhotoForExternalResource($default); + } else { + $photo = MPhoto::createPhotoForSystemResource($default); + } } return $photo; }