Cách Upload File Trên Laravel

Cách Upload File Trên Laravel
Sau khi đã giới thiệu cho các bạn biết về request, response,…Bài hôm nay sẽ hướng dẫn cho các bạn về cách upload file trên Laravel như thế nào.

Đăng tải và cập nhật các file là một trong các tính năng phổ biến khi thao tác trên website. Đó cũng là tính năng dễ dàng vì các bạn thực hiện 4 thao tác cơ bản: form, submit, validation và store. Nó có thể hơi phức tạp khi bạn cho phép người dùng tải lên nhiều tập tin trong cùng một khoảng thời gian trên Laravel. 

 

Chuẩn bị dữ liệu 

 

Dùng bảng products với 2 trường (name và image của trường) để tạo models và migration qua câu lệnh: 

 

php artisan make:model Product -m

php artisan make:model ProductsPhoto -m

 

Tham số -m này là migration sẽ được tạo cùng với model. File app/Models/Product.php sẽ là:

namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
    protected $fillable = ['name'];
}

 

Migration của bảng products sẽ như sau:

 

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProductsTable extends Migration
{
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::drop('products');
    }
}

 

Tiếp theo, các bạn tạo mối quan hệ giữa hai bảng products và products_photos qua model app/ProductsPhoto.php

 

namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ProductsPhoto extends Model
{
    protected $fillable = ['product_id', 'filename'];
    public function product()
    {
        return $this->belongsTo('App\Product');
    }
}

 

Khi đã có các dòng lệnh trên, bạn tạo thêm migration cho bảng products_photos:

 

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Database\Migrations\Migration;

class CreateProductsPhotosTable extends Migration

{

    public function up()

    {

        Schema::create('products_photos', function (Blueprint $table) {

            $table->increments('id');

            $table->integer('product_id')->unsigned();

            $table->foreign('product_id')->references('id')->on('products');

            $table->string('filename');

            $table->timestamps();

        });

    }

    public function down()

    {

        Schema::drop('products_photos');

    }

}

 

Tạo cấu trúc routes, controllers và views 

 

Các bạn nên bắt đầu với trang upload form và trang kết quả. Nên dùng 2 routes và 1 controller. Tiến hành file routes/web.php như sau: 

 

Route::get('/upload', '[email protected]');
Route::post('/upload', '[email protected]');
Sau đó, bạn tạo 1 controller và có chứa 1 command làm việc: 
php artisan make:controller UploadController

 

Khi có 1 command làm việc, bạn để vào controller tạm thời như vậy: 

 

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UploadController extends Controller

{

    public function uploadForm()

    {

        return view('upload_form');

    }

    public function uploadSubmit(Request $request)

    {

        // Coming soon...

    }

}

 

Kiểm tra các phần bạn vừa làm có ổn hay không bằng cách thử chạy URL/upload trên trình duyệt. 

 

 

Nếu thấy có 2 dòng hiện ra như trên, thì đó là thông báo lỗi. Lỗi đó là route và controller đã ổn. Bạn còn đang bị thiếu phần view. Chúng ta tiếp tục tạo ra view. 

 

Cách tạo view cho phần upload form 

 

Đối với form này, bạn chỉ cần sử dụng các thẻ HTML mặc định. Bạn không phải dùng thêm bất cứ package form nào. Form khi đó sẽ như thế này: 

 

<form action="/upload" enctype="multipart/form-data" method="post">
    {{ csrf_field() }} 
    Product name: <br />
    <input name="name" type="text"> 
    <br /><br />
    Product photos (can attach more than one): <br />
   <input multiple="multiple" name="photos[]" type="file"> 
   <br /><br />
   <input type="submit" value="Upload">
</form>

 

 

Đừng quên validation request 

 

Bạn quay lại controller và điền vào method uploadSubmit(). Trước khi tải tập tin lên, bạn nên validate dữ liệu trước vì như vậy tập tin của bạn sẽ mượt và an toàn. Ví dụ bạn có tên sản phẩm và hình có dung lượng không quá 2MB. Bạn tạo một file validation request như sau: 

 

php artisan make:request UploadRequest

 

Khi đã gõ dòng lệnh đó, bạn mở file app/Http/Requests/UploadRequest.php

 

class UploadRequest extends FormRequest
{
    public function authorize()
    {
        return false;
    }
    public function rules()
    {
        return [
            //
        ];
    }
}

 

Bạn phải sửa method authorize() để chuyển về true. Nếu không làm như vậy, bạn sẽ không thể qua được khi submit. Tiếp theo, bạn cần chú ý đến method rules(). Bạn thêm tên sản phẩm. Không nên để trống chỗ đó. 

 

return [
    'name' => 'required'
];

 

Sau đó, bạn nên validate cho hình. Nếu bạn chỉ có 1 ảnh trường, thì nó sẽ hiện ra như vậy: 

 

return [
    'name' => 'required',
    'photo' => 'image|mimes:jpeg,bmp,png|size:2000'
];

 

Nếu có nhiều hơn 1 tập tin thì phải làm thế nào? Bạn nên điền vào các rules() trong một mảng linh hoạt với một vòng lặp:

 

public function rules()
{
    $rules = [
        'name' => 'required'
    ];
    $photos = count($this->input('photos'));
    foreach(range(0, $photos) as $index) {
        $rules['photos.' . $index] = 'image|mimes:jpeg,bmp,png|max:2000';
    }
    return $rules;
}

 

Bạn cần đưa file request đó cho controller. Nên thay đổi tham số của method và use nó trước khi đưa qua controller. 

 

namespace App\Http\Controllers;
use App\Http\Requests\UploadRequest;
class UploadController extends Controller
{
    public function uploadForm()
    {
        return view('upload_form');
    }
    public function uploadSubmit(UploadRequest $request)
    {
        // Coming soon...
    }
}

 

Nếu lúc cập nhật dữ liệu lên có lỗi, bạn sẽ thấy có thông báo như thế này: 

 

@if (count($errors) > 0)
    <ul><li>{{ $error }}</li></ul>
@endif
<form action="/upload" enctype="multipart/form-data" method="post">...</form>

 

Nếu bạn không nhập tên sản phẩm và tải hình ảnh có dung lượng lớn, thì bạn sẽ thấy màn hình hiển thị như vậy: 

 

 

Cách lưu dữ liệu 

 

Khi đã tải dữ liệu lên, thì bạn nên thực hiện thêm một bước nữa. Đó là lưu dữ liệu. Database và file storage là 2 yếu tố thiết yếu cần quan tâm. Bắt đầu với các tập tin và tìm hiểu thêm về filesystems trong Laravel. Có một tập tin config/filesystems.php là nơi bạn chỉ định vị trí lưu trữ tập tin. Nó cho phép bạn định dạng cấu hình bộ nhớ ngoài như Amazon S3. Chuyện cấu hình đó như thế nào thì tính sau. Lúc này đây, bạn cần tập trung vào các tham số mặc định. 

 

return [
    'default' => 'local',
    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],
    // ...

 

Tất cả các tập tin của bạn sẽ được lưu trong thư mục /storage/app và không nằm ở /public. Điều đó giúp các tập tin được bảo mật và an toàn hơn. Không ai có thể truy cập trực tiếp từ URL của trình duyệt. Bạn cũng có thể thay đổi tập tin (nếu cần). Việc tải tập tin trong Laravel không khó. Toàn bộ phương thức controller sẽ giống như vậy: 

 

public function uploadSubmit(UploadRequest $request)
{
    $product = Product::create($request->all());
    foreach ($request->photos as $photo) {
        $filename = $photo->store('photos');
        ProductsPhoto::create([
            'product_id' => $product->id,
            'filename' => $filename
        ]);
    }
    return 'Upload successful!';
}

 

Để tải tập tin, bạn dùng lệnh $photo->store(‘photos’). Tham số kia là xác định thư mục nào là thư mục con để được sử dụng hoặc lưu trữ. Trong tình huống này, nó sẽ trở thành /storage/app/photos. Tên của tập tin sẽ được tạo thành một chuỗi ngẫu nhiên và tự động. 

 

Trong database thì sẽ như thế này: 

 

Bạn có thể thực hiện thêm nhiều validate, thay đổi kích thước hình ảnh, thu nhỏ hình và nhiều chức năng hơn nữa. 

 

Trong bài này, các bạn sẽ thấy cách đăng tải file khá đơn giản trên Laravel. Trên thực tế, các bạn cần validate dung lượng file upload lên, phân loại file sao cho phù hợp,…Điều đó giúp cho ứng dụng hoặc web của bạn an toàn nhất có thể.

 

Hồ Hữu Hiền

Mình là developer nên đôi khi viết bài không hay lắm mong các bạn thông cảm. Nếu muốn biết thêm thông tin về mình thì vui lòng vào website này để biết. https://huuhienqt.dev/

Bình luận (1)