KiwiFinn's avatar

Can't get file contents with GET but can with POST

I'm building an application in Laravel that requires users to upload documents. To maintain a high level of security around these documents, they must be stored in the "private" storage. I'm able to upload and store them successfully and I can access the file contents if I use a Route with a POST however if I try to use a GET method in an img src tag to display an image inline the image doesn't render.

What I have noticed is if I copy and paste the image location (by inspecting the rendered view) into another browser tab, the token is completely different, the browser tab is effectively not logged in, so the image is unavailable and I get a 404 error. This is fine in terms of protecting the documents and I'm very happy about that, but I would really like the image to be able to display inline as well.

No suggestions about using public storage etc, this will not work for my application.

Code is as follows: In the blade

<img src="{{ route('showJpg',$document->filename) }}" class="img-responsive" width="100%">

Sample output from rendered view

<img src="http://nzm.local/admin/showImage/Wilson-Family/KzzaeTBaeORqgr8SFbLE7B4ODF5P2waGlvC7vS7F.jpeg" class="img-responsive" width="100%">

POST Method (takes Request as parameter)

  public function getFile(Request $request)
  {
      $filename = $request->filename;
      $file = Storage::get($filename);

      if ($file) {

        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $header[] = ($ext=="pdf" ? "'Content-Type', 'application/pdf'" : "'Content-Type', 'image/jpeg'");

        return response()->file(storage_path('/app/'.$filename), $header);

      } else {
        dd("No file");
      }
  }

GET Method (takes filename as parameter)

  public function viewjpg($filename)
  {
    //
    $file = Storage::get($filename);

    if ($file) {

      $ext = pathinfo($filename, PATHINFO_EXTENSION);
      $header[] = ($ext=="pdf" ? "'Content-Type', 'application/pdf'" : "'Content-Type', 'image/jpeg'");

      return response()->file(storage_path('/app/'.$filename), $header);

    } else {
      dd("No file");
    }
  }

Neither of these methods hit the dd("No file") as the image exists and is clearly readable by the application. The problem is with the GET method and the token, as far as I tell.

Any assistance greatly appreciated, have been chasing my own tail for a while now and not making any headway at all.

0 likes
10 replies
markus.heb's avatar

Can you please show me your routes/web.php file (or the corresponding part)

Maybe there is something wrong.

Snapey's avatar
Snapey
Best Answer
Level 122

Do you have to have a slash in the filename? The router is treating this as two parts not one.

So, for instance

Route::get('/admin/showImage/{filename}' 

only accepts one parameter, but you provide two in Wilson-Family/KzzaeTBaeORqgr8SFbLE7B4ODF5P2waGlvC7vS7F.jpeg

Alternatively, pass the filename as a query parameter and then get it from the request object, so your URL is more like

http://nzm.local/admin/showImage?f=Wilson-Family/KzzaeTBaeORqgr8SFbLE7B4ODF5P2waGlvC7vS7F.jpeg

in the controller;

$file = Storage::get($request->f);
KiwiFinn's avatar

Thank you markus.heb

web.php for the two routes in question

  Route::post('showfile/', 'DocumentsController@getFile')->name('viewDocument');
  Route::get('showImage/{filename}', 'DocumentsController@viewjpg')->name('showJpg');

Once I get the GET method working, I will ditch the POST method. I don't remember what inspired me to try the POST in the first place, but it worked so I was able to continue on with my development.

KiwiFinn's avatar

@SNAPEY - Thanks SNAPEY, I totally get your answer - seems really obvious now. I've modified my blade and get this in my output

<img src="/admin/showImage?f=Wilson-Family/KzzaeTBaeORqgr8SFbLE7B4ODF5P2waGlvC7vS7F.jpeg" class="img-responsive" width="100%">

And tweaked my controller thus:

  public function viewjpg(Request $request)
  {
  
    $file = Storage::get($request->f);

And still getting the same result. The thing that I continue to notice is if I check the URL for the main page using Debugbar, it shows that I have auth status and shows me logged in but if I switch to the URL that is getting the image, I'm not logged in. That bit doesn't make sense, but with that piece of information, it is no surprise that the image is not showing.

Snapey's avatar

Did you change the route to suit?

You don't get 404 from being unauthenticated

KiwiFinn's avatar

Have set my route to

Route::prefix('admin')->group(function() {
     Route::get('showImage', 'DocumentsController@viewjpg')->name('showJpg');
.
.
.
}
1 like
Snapey's avatar

Can you check the parameter is passed ok.

public function viewjpg(Request $request)
  {
  
    dd($request->f);

    $file = Storage::get($request->f);

and then open your image URL in your browser

KiwiFinn's avatar

Solved! Thank you @snapey. I ran php artisan route:cache which I don't think I did after changing the route before and now I'm getting exactly what I want.

Cheers

Snapey's avatar

ideally in development you would run route:clear and then only in production run route:cache

Please or to participate in this conversation.