Skip to content

Instantly share code, notes, and snippets.

@ajaxray
Created July 2, 2024 09:55
Show Gist options
  • Select an option

  • Save ajaxray/5d8cd57aba4e39cc56924318ce869b8c to your computer and use it in GitHub Desktop.

Select an option

Save ajaxray/5d8cd57aba4e39cc56924318ce869b8c to your computer and use it in GitHub Desktop.

Revisions

  1. ajaxray created this gist Jul 2, 2024.
    11 changes: 11 additions & 0 deletions 1_README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    # Upload files to object storage / CDN directly from the Frontend

    This is a demonstration of uploading files to S3 compliant storage.
    This implementation is using Laravel (backend) and AlpineJS (frontend).

    ### How it works

    1. User selects a file on frontend
    2. Javascript makes a request to the backend for getting a [TemporaryUploadUrl](https://laravel.com/docs/11.x/filesystem#temporary-upload-urls).
    3. On receiving the signed, temporary URL, Javascript pushes the file to S3 directly from front-end.
    4. After the upload is done, we have the CDB URL of the file (to submit and store in backend).
    25 changes: 25 additions & 0 deletions S3DirectUploadController.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    <?php

    namespace App\Http\Controllers;

    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Storage;

    class S3DirectUploadController extends Controller
    {
    public function getTemporaryUploadUrl(Request $request)
    {
    $validatedData = $request->validate([
    'fileName' => 'required|string',
    ]);

    $fileName = $validatedData['fileName'];
    $path = 'direct_uploads/' . uniqid() . '-' . $fileName;

    ['url' => $url, 'headers' => $headers] = Storage::disk('s3')->temporaryUploadUrl(
    $path, now()->addMinutes(5)
    );

    return response()->json(['url' => $url, 'filePath' => $path]);
    }
    }
    89 changes: 89 additions & 0 deletions s3_direct.blade.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    <x-app-layout>
    <x-slot name="header">
    <h2 class="font-semibold text-xl text-gray-800 leading-tight">
    {{ __('Direct CDN Upload') }}
    </h2>
    </x-slot>

    <div class="py-12">
    <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
    <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">

    <div x-data="fileUpload()" class="p-6">
    <form @submit.prevent="uploadFile">
    <input type="file" x-ref="fileInput">
    <button class="px-4 py-2 bg-blue-500 text-white rounded" type="submit">Upload</button>
    </form>

    <template x-if="isUploading">
    <p class="p-4 text-orange-400">Uploading...</p>
    </template>

    <template x-if="uploadSuccess">
    <p class="p4 text-green-600">Upload successful! File path: <span x-text="filePath"></span></p>
    </template>
    </div>

    </div>
    </div>
    </div>

    <script>
    function fileUpload() {
    return {
    isUploading: false,
    uploadSuccess: false,
    filePath: '',
    async uploadFile() {
    this.isUploading = true;
    this.uploadSuccess = false;
    const file = this.$refs.fileInput.files[0];
    if (!file) {
    alert('Please select a file.');
    this.isUploading = false;
    return;
    }
    try {
    // Step 1: Get temporary upload URL
    const response = await fetch('/upload/s3-get-upload-url', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
    },
    body: JSON.stringify({
    fileName: file.name
    })
    });
    const data = await response.json();
    const uploadUrl = data.url;
    this.filePath = data.filePath;
    // Step 2: Upload the file to S3 using the temporary URL
    const uploadResponse = await fetch(uploadUrl, {
    method: 'PUT',
    headers: {
    'Content-Type': file.type
    },
    body: file
    });
    if (uploadResponse.ok) {
    this.uploadSuccess = true;
    } else {
    alert('Failed to upload file.');
    }
    } catch (error) {
    console.error('Error uploading file:', error);
    alert('An error occurred while uploading the file.');
    } finally {
    this.isUploading = false;
    }
    }
    };
    }
    </script>
    </x-app-layout>
    17 changes: 17 additions & 0 deletions web.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    <?php

    use App\Http\Controllers\S3DirectUploadController;
    use Illuminate\Support\Facades\Route;

    // Other Routes ...

    Route::middleware('auth')->group(function () {

    // Other Routes ...

    Route::view('/upload/s3-direct', 'upload.s3_direct');
    Route::post('/upload/s3-get-upload-url', [S3DirectUploadController::class, 'getTemporaryUploadUrl']);

    });

    require __DIR__.'/auth.php';