X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FProxy.php;h=4d1e1c304b082e912ef54abe6d70756e5b96ceb6;hb=7fd1db0ec6b3c729e347f94ca961421fb4f5070e;hp=317ec530a5335ab22dc9024182087ba21de09dc4;hpb=2b95a7e7cd76c573b82b2dbcc5ad08b1501ee89b;p=friendica.git diff --git a/src/Module/Proxy.php b/src/Module/Proxy.php index 317ec530a5..4d1e1c304b 100644 --- a/src/Module/Proxy.php +++ b/src/Module/Proxy.php @@ -1,6 +1,6 @@ getRequestInfo(); - /* - * Pictures are stored in one of the following ways: - * - * 1. If a folder "proxy" exists and is writeable, then use this for caching - * 2. If a cache path is defined, use this - * 3. If everything else failed, cache into the database - * - * Question: Do we really need these three methods? - */ - if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MATCH'])) { - header('HTTP/1.1 304 Not Modified'); + if (!DI::config()->get('system', 'proxify_content')) { + Logger::notice('Proxy access is forbidden', ['request' => $request, 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'accept' => $_SERVER['HTTP_ACCEPT'] ?? '']); + throw new \Friendica\Network\HTTPException\NotFoundException(); + } + + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']); + if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) { + header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']); + } header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); header('Cache-Control: max-age=31536000'); - if (function_exists('header_remove')) { header_remove('Last-Modified'); header_remove('Expires'); header_remove('Cache-Control'); } - - /// @TODO Stop here? - exit(); - } - - if (function_exists('header_remove')) { - header_remove('Pragma'); - header_remove('pragma'); + throw new NotModifiedException(); } - $direct_cache = self::setupDirectCache(); - - $request = self::getRequestInfo(); - if (empty($request['url'])) { throw new \Friendica\Network\HTTPException\BadRequestException(); } - if (!local_user()) { - Logger::info('Redirecting not logged in user to original address', ['url' => $request['url']]); + if (!DI::userSession()->getLocalUserId()) { + Logger::debug('Redirecting not logged in user to original address', ['url' => $request['url']]); System::externalRedirect($request['url']); } - // Webserver already tried direct cache... - - // Try to use filecache; - $cachefile = self::responseFromCache($request); - - // Try to use photo from db - self::responseFromDB($request); - - // - // If script is here, the requested url has never cached before. - // Let's fetch it, scale it if required, then save it in cache. - // - // It shouldn't happen but it does - spaces in URL $request['url'] = str_replace(' ', '+', $request['url']); - $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), ['timeout' => 10]); - $img_str = $fetchResult->getBody(); - // If there is an error then return a blank image - if ((substr($fetchResult->getReturnCode(), 0, 1) == '4') || empty($img_str)) { - Logger::info('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]); + // Fetch the content with the local user + try { + $fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]); + $img_str = $fetchResult->getBody(); + + if (!$fetchResult->isSuccess() || empty($img_str)) { + Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]); + self::responseError(); + // stop. + } + } catch (\Exception $exception) { + Logger::notice('Error fetching image', ['image' => $request['url'], 'exception' => $exception]); self::responseError(); - // stop. } - $tempfile = tempnam(get_temppath(), 'cache'); - file_put_contents($tempfile, $img_str); - $mime = mime_content_type($tempfile); - unlink($tempfile); + Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]); + + $mime = Images::getMimeTypeByData($img_str); $image = new Image($img_str, $mime); if (!$image->isValid()) { - Logger::info('The image is invalid', ['image' => $request['url'], 'mime' => $mime]); + Logger::notice('The image is invalid', ['image' => $request['url'], 'mime' => $mime]); self::responseError(); // stop. } - $basepath = $a->getBasePath(); - $filepermission = DI::config()->get('system', 'proxy_file_chmod'); - - // Store original image - if ($direct_cache) { - // direct cache , store under ./proxy/ - $filename = $basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true); - file_put_contents($filename, $image->asString()); - if (!empty($filepermission)) { - chmod($filename, $filepermission); - } - } elseif($cachefile !== '') { - // cache file - file_put_contents($cachefile, $image->asString()); - } else { - // database - Photo::store($image, 0, 0, $request['urlhash'], $request['url'], '', 100); - } - - // reduce quality - if it isn't a GIF if ($image->getType() != 'image/gif') { $image->scaleDown($request['size']); } - - // Store scaled image - if ($direct_cache && $request['sizetype'] != '') { - $filename = $basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true) . $request['sizetype']; - file_put_contents($filename, $image->asString()); - if (!empty($filepermission)) { - chmod($filename, $filepermission); - } - } - self::responseImageHttpCache($image); // stop. } - /** * Build info about requested image to be proxied * * @return array * [ * 'url' => requested url, - * 'urlhash' => sha1 has of the url prefixed with 'pic:', * 'size' => requested image size (int) * 'sizetype' => requested image size (string): ':micro', ':thumb', ':small', ':medium', ':large' * ] * @throws \Exception */ - private static function getRequestInfo() + private function getRequestInfo(): array { - $a = DI::app(); $size = ProxyUtils::PIXEL_LARGE; $sizetype = ''; - // Look for filename in the arguments - // @TODO: Replace with parameter from router - if (($a->argc > 1) && !isset($_REQUEST['url'])) { - if (isset($a->argv[3])) { - $url = $a->argv[3]; - } elseif (isset($a->argv[2])) { - $url = $a->argv[2]; - } else { - $url = $a->argv[1]; - } - - /// @TODO: Why? And what about $url in this case? - /// @TODO: Replace with parameter from router - if (isset($a->argv[3]) && ($a->argv[3] == 'thumb')) { - $size = 200; - } + if (!empty($this->parameters['url']) && empty($_REQUEST['url'])) { + $url = $this->parameters['url']; // thumb, small, medium and large. if (substr($url, -6) == ':micro') { @@ -238,87 +167,17 @@ class Proxy extends BaseModule $url = str_replace(['.jpg', '.jpeg', '.gif', '.png'], ['','','',''], $url); $url = base64_decode(strtr($url, '-_', '+/'), true); - } else { $url = $_REQUEST['url'] ?? ''; } return [ 'url' => $url, - 'urlhash' => 'pic:' . sha1($url), 'size' => $size, 'sizetype' => $sizetype, ]; } - - /** - * setup ./proxy folder for direct cache - * - * @return bool False if direct cache can't be used. - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ - private static function setupDirectCache() - { - $a = DI::app(); - $basepath = $a->getBasePath(); - - // If the cache path isn't there, try to create it - if (!is_dir($basepath . '/proxy') && is_writable($basepath)) { - mkdir($basepath . '/proxy'); - } - - // Checking if caching into a folder in the webroot is activated and working - $direct_cache = (is_dir($basepath . '/proxy') && is_writable($basepath . '/proxy')); - // we don't use direct cache if image url is passed in args and not in querystring - $direct_cache = $direct_cache && ($a->argc > 1) && !isset($_REQUEST['url']); - - return $direct_cache; - } - - - /** - * Try to reply with image in cachefile - * - * @param array $request Array from getRequestInfo - * - * @return string Cache file name, empty string if cache is not enabled. - * - * If cachefile exists, script ends here and this function will never returns - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \ImagickException - */ - private static function responseFromCache(&$request) - { - $cachefile = get_cachefile(hash('md5', $request['url'])); - if ($cachefile != '' && file_exists($cachefile)) { - $img = new Image(file_get_contents($cachefile), mime_content_type($cachefile)); - self::responseImageHttpCache($img); - // stop. - } - return $cachefile; - } - - /** - * Try to reply with image in database - * - * @param array $request Array from getRequestInfo - * - * If the image exists in database, then script ends here and this function will never returns - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \ImagickException - */ - private static function responseFromDB(&$request) - { - $photo = Photo::getPhoto($request['urlhash']); - - if ($photo !== false) { - $img = Photo::getImageForPhoto($photo); - self::responseImageHttpCache($img); - // stop. - } - } - /** * In case of an error just stop. We don't return content to avoid caching problems * @@ -333,12 +192,13 @@ class Proxy extends BaseModule * Output the image with cache headers * * @param Image $img + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function responseImageHttpCache(Image $img) { if (is_null($img) || !$img->isValid()) { - Logger::info('The cached image is invalid'); + Logger::notice('The cached image is invalid'); self::responseError(); // stop. } @@ -348,6 +208,6 @@ class Proxy extends BaseModule header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); header('Cache-Control: max-age=31536000'); echo $img->asString(); - exit(); + System::exit(); } }