authorizeForUser($this->getUser(), 'view', $album); if (UserConfig::get('hotlink_protection')) { $referrer = $request->headers->get('Referer'); if (!is_null($referrer)) { $hostname = parse_url($referrer, PHP_URL_HOST); if (strtolower($hostname) != strtolower($request->getHttpHost())) { App::abort(403); return null; } } else { App::abort(403); return null; } } $photo = PhotoController::loadPhotoByAlbumAndFilename($album, $photoFilename); $thumbnail = $request->get('t'); if (is_null($thumbnail)) { $this->authorizeForUser($this->getUser(), 'photo.download_original', $photo); } // Record the visit to the photo if (UserConfig::get('enable_visitor_hits')) { DB::transaction(function () use ($album, $photo, $request, $thumbnail) { $photo->hits_download++; $photo->save(); VisitorHit::fromRequest($request, $album->id, $photo->id, (is_null($thumbnail) ? 'original' : $thumbnail)); }); } /** @var Stream $photoStream */ $photoStream = $album->getAlbumSource()->fetchPhotoContent($photo, $thumbnail); $mimeType = mimetype_from_extension(pathinfo($photo->storage_file_name, PATHINFO_EXTENSION)); return response()->stream( function() use ($photoStream) { echo $photoStream; }, 200, [ 'Content-Length' => strlen($photoStream->getContents()), 'Content-Type' => $mimeType ] ); } public function show(Request $request, $albumUrlAlias, $photoFilename) { $album = DbHelper::getAlbumByPath($albumUrlAlias); if (is_null($album)) { App::abort(404); return null; } $this->authorizeForUser($this->getUser(), 'view', $album); $photo = PhotoController::loadPhotoByAlbumAndFilename($album, $photoFilename); $isOriginalAllowed = Gate::forUser($this->getUser())->allows('photo.download_original', $photo); // Load the Next/Previous buttons $thisPhotoDate = is_null($photo->taken_at) ? $photo->created_at : $photo->taken_at; // I don't like the idea of using a totally raw SQL query, but it's the only sure-fire way to number the rows // so we can get the previous/next photos accurately - and we don't have to load all data for the photo objects $previousPhoto = null; $nextPhoto = null; $allAlbumPhotos = DB::select( DB::raw( 'SELECT p.id, (@row_number:=@row_number + 1) AS row_number FROM photos p, (SELECT @row_number:=0) AS t WHERE p.album_id = :album_id ORDER BY COALESCE(p.taken_at, p.created_at), p.name, p.id;' ), [ 'album_id' => $album->id ] ); for ($i = 0; $i < count($allAlbumPhotos); $i++) { if ($allAlbumPhotos[$i]->id === $photo->id) { if ($i > 0) { $previousPhoto = Photo::where('id', $allAlbumPhotos[$i - 1]->id)->first(); } if ($i + 1 < count($allAlbumPhotos)) { $nextPhoto = Photo::where('id', $allAlbumPhotos[$i + 1]->id)->first(); } break; } } // Record the visit to the photo if (UserConfig::get('enable_visitor_hits')) { DB::transaction(function () use ($album, $photo, $request) { $photo->hits++; $photo->save(); VisitorHit::fromRequest($request, $album->id, $photo->id); }); } return Theme::render('gallery.photo', [ 'album' => $album, 'is_original_allowed' => $isOriginalAllowed, 'next_photo' => $nextPhoto, 'photo' => $photo, 'previous_photo' => $previousPhoto, 'success' => $request->getSession()->get('success') ]); } public function showExifData(Request $request, $albumUrlAlias, $photoFilename) { $album = DbHelper::getAlbumByPath($albumUrlAlias); if (is_null($album)) { App::abort(404); return null; } $this->authorizeForUser($this->getUser(), 'view', $album); $photo = PhotoController::loadPhotoByAlbumAndFilename($album, $photoFilename); $this->authorizeForUser($this->getUser(), 'changeMetadata', $photo); $exifData = print_r(unserialize(base64_decode($photo->raw_exif_data)), true); return Theme::render('gallery.photo_exif', [ 'album' => $album, 'exif_data' => $exifData, 'photo' => $photo ]); } /** * @param $id * @return Photo */ public static function loadPhotoByAlbumAndFilename(Album $album, $filename) { $photo = Photo::where([ ['album_id', $album->id], ['storage_file_name', $filename] ])->first(); if (is_null($photo)) { App::abort(404); return null; } return $photo; } }