Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

muuucho's avatar
Level 11

Displaying a pdf that is stored in a remote storage

I have a script that uploads a image file or pdf to a remote server using SFTP. The script should also display the uploaded file. The upload part is running as expected but the file doesn't display, instead, what appears to be another image is displayed (it seems to be a screenshot of one of my projects, I don't know where it is stored). What is wrong?

routes:

Route::get('/file-upload', [FileController::class, 'showUploadForm']);
Route::post('/file-upload', [FileController::class, 'store']);
Route::get('/file/{filename}', [FileController::class, 'serveFile']);

Controller:

View:

<form action="/file-upload" method="post" enctype="multipart/form-data">
    @csrf
    <input type="file" name="file">
    <button type="submit">Upload</button>
</form>
@if (session('message'))
    <p>{{ session('message') }}</p>
@endif

@foreach($files as $file)
    {{ $file->name }}
    <br>
    <embed src="{{ $file->name }}" width="600" height="400">
@endforeach
0 likes
2 replies
LaryAI's avatar
Level 58

To display a PDF stored on a remote server using SFTP, you need to ensure that the URL used in the <embed> tag is correctly pointing to a route that serves the file. Here are some steps and corrections you can make to ensure the PDF is displayed correctly:

  1. Correct the URL in the View: Ensure that the URL in the <embed> tag points to the correct route that serves the file. You should use the route() helper to generate the URL for the serveFile route.

    Update your view to use the correct URL:

    @foreach($files as $file)
        {{ $file->name }}
        <br>
        <embed src="{{ route('file.serve', ['filename' => $file->name]) }}" width="600" height="400">
    @endforeach
    
  2. Define Named Route: Make sure your route for serving the file is named so you can reference it easily in your view.

    Update your routes file:

    Route::get('/file/{filename}', [FileController::class, 'serveFile'])->name('file.serve');
    
  3. Ensure Correct MIME Type Detection: The File::mimeType() method you are using might not be correct. Instead, use the finfo_file() function to determine the MIME type.

    Update the serveFile method in your controller:

    public function serveFile($filename)
    {
        $disk = Storage::disk('sftp');
    
        if (!$disk->exists($filename)) {
            abort(404, 'File not found');
        }
    
        $fileData = $disk->get($filename);
    
        // Determine the MIME type
        $tempFilePath = sys_get_temp_dir() . '/' . $filename;
        file_put_contents($tempFilePath, $fileData);
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $tempFilePath);
        finfo_close($finfo);
        unlink($tempFilePath);
    
        return response($fileData, 200)
            ->header('Content-Type', $mimeType);
    }
    
  4. Check File Path: Ensure that the file path stored in your database is correct and matches the path used in the SFTP storage. The path should be relative to the root of the SFTP storage.

By following these steps, you should be able to correctly display the PDF files stored on your remote server. Make sure to test the file paths and MIME type detection to ensure everything is working as expected.

muuucho's avatar
muuucho
OP
Best Answer
Level 11

I corrected how I embed the file to this:

<embed src="{{ route('file.serve', ['filename' => $file->name]) }}" width="600" height="400">

...and change the route accordingly. If I skip the folder uploads everything works fine. But if I like to store uploaded files in a subfolder I get the error The route file/uploads/hE95GzSs1kKAgiG8fmAsJMvgF92hiTDymkdfS0WM.pdf could not be found. I guess that the route can not handle this call. How can I solve this? I also tried to tweak the file name:

<embed src="{{ route('file.serve', ['filename' => urlencode($file->name)]) }}" width="600" height="400">

And then take it back in the controller:

public function serveFile($filename)
    {
        $filename = urldecode($filename);
		...

But then I get The requested URL was not found on this server.

UPDATE: The route doesn't even hit the serveFile(), when I log from there, nothing is written to the log file.

UPDATE2: On my remote server I have the same problem, log file says [2024-10-10 16:37:29] staging.ERROR: file_put_contents(/tmp/uploads/ImsqKRjpjy7CSrv4CW3UV27JHv8rEUbKdrhBhrjx.jpg): Failed to open stream: No such file or directory {"userId":1,"exception":"[object] (ErrorException(code: 0): file_put_contents(/tmp/uploads/ImsqKRjpjy7CSrv4CW3UV27JHv8rEUbKdrhBhrjx.jpg): Failed to open stream: No such file or directory at /home/my-path/laravel/app/Http/Controllers/FileController.php:53) [stacktrace] UPDATE3: Don't do urlencode/urldecode. Instead change the route to this:

Route::get('/file/{filename}', [FileController::class, 'serveFile'])
    ->where('filename', '.*')
    ->name('file.serve');

Solution here: https://stackoverflow.com/questions/21552604/how-to-define-a-laravel-route-with-a-parameter-that-contains-a-slash-character

1 like

Please or to participate in this conversation.