Hướng dẫn Laravel cho người mới bắt đầu
⚡ Tóm tắt thông minh
Laravel là một framework PHP MVC mã nguồn mở được tạo bởi Taylor Otwell để xây dựng các ứng dụng web một cách nhanh chóng và hiệu quả. Hướng dẫn này giải thích Laravel là gì, cách cài đặt nó bằng Composer và xây dựng một ứng dụng tải lên tập tin hoạt động bằng cách sử dụng định tuyến, bộ điều khiển, xác thực yêu cầu biểu mẫu và các mẫu Blade.
Laravel là gì?
Laravel là một khung công tác web MVC mã nguồn mở dành cho PHP. Laravel là một framework mạnh mẽ giúp phát triển dễ dàng các ứng dụng web PHP với các tính năng như hệ thống đóng gói mô-đun với trình quản lý phụ thuộc chuyên dụng, quyền truy cập vào cơ sở dữ liệu quan hệ và các tiện ích khác để triển khai và bảo trì ứng dụng.
Laravel được tạo ra bởi Taylor Otwell. Kể từ lần phát hành đầu tiên vào tháng 6 năm 2011 (phiên bản 1), nó đã ngày càng trở nên phổ biến trong lĩnh vực framework PHP của ngành phát triển web. Phần lớn sự phổ biến này có thể được lý giải bởi nhiều tính năng ưu tiên lập trình viên được tích hợp sẵn.
Tại sao lại là Laravel?
Khoảng năm 2000, hầu hết Mã PHP mang tính thủ tục và có thể được tìm thấy ở dạng “tập lệnh” có một mớ mã spaghetti lộn xộn. Ngay cả những trang đơn giản nhất cũng không có tách biệt các mối quan tâmVà do đó, một ứng dụng rất dễ nhanh chóng trở thành một cơn ác mộng về bảo trì. Thế giới cần một giải pháp tốt hơn. Và thế là PHP phiên bản 5 cùng nhiều framework PHP khác ra đời, nhằm mang lại cấu trúc cần thiết và các giải pháp tốt hơn cho nhiều vấn đề của ứng dụng web.
Kể từ đó, chúng ta đã chứng kiến sự ra đời của nhiều framework, mở đường cho các framework phổ biến được sử dụng ngày nay. Hiện nay, ba framework hàng đầu (theo ý kiến của chúng tôi) là Zend Framework, Symfony và tất nhiên là Laravel. Mặc dù mỗi framework này đều được xây dựng trên những nguyên tắc tương tự và hướng đến giải quyết (về cơ bản) cùng những vấn đề phổ biến, nhưng sự khác biệt chính nằm ở cách triển khai. Mỗi framework đều có những đặc điểm riêng trong cách giải quyết vấn đề. Khi xem xét mã nguồn của từng framework, bạn sẽ thấy một ranh giới khá rõ ràng giữa chúng. Theo ý kiến khiêm tốn của chúng tôi, framework Laravel là tốt nhất.
Tìm hiểu thêm về sự khác biệt giữa Laravel và CodeIgnite.
Cách tải xuống và cài đặt Laravel với Composer
Lưu ý: Hướng dẫn này được viết cho Laravel 5.8, nhưng các khái niệm về định tuyến, bộ điều khiển, yêu cầu và Blade vẫn giữ nguyên trong các phiên bản hiện tại. Tính đến năm 2026, phiên bản mới nhất là Laravel 13 (phát hành tháng 3 năm 2026), yêu cầu PHP 8.3 trở lên, trong khi Laravel 12 yêu cầu PHP 8.2.
Lưu ý: Giả định rằng bạn đã cài đặt PHP trên hệ thống máy tính của mình. Nếu chưa, bạn có thể đọc hướng dẫn cài đặt PHP. đây.
Composer vừa là trình quản lý gói vừa là trình quản lý phụ thuộc. Để cài đặt nó, hãy mở terminal và cd vào một thư mục mới. Chạy lệnh này:
curl -Ss getcomposer.org/installer | php
Kết quả của lệnh này sẽ như thế này:
Lưu ý: Để có hướng dẫn chi tiết hơn về cách thiết lập Laravel, hãy tham khảo tài liệu Laravel. đây.
Bạn sẽ thấy quá trình tải xuống và biên dịch tập lệnh composer.phar, đây là tập lệnh chúng ta sử dụng để cài đặt Laravel. Mặc dù có rất nhiều cách để thiết lập một ứng dụng Laravel mới, chúng ta sẽ thực hiện thông qua tập lệnh composer của Laravel. Để cài đặt tập lệnh này, hãy chạy lệnh sau:
composer global require laravel/installer
Nó sẽ trông giống như thế này:
Thao tác này sẽ tải xuống và cài đặt tất cả các tệp khung cũng như tất cả các thư viện phụ thuộc cần thiết. Các gói sẽ được lưu trong thư mục vendor. Sau khi tải xuống và cài đặt xong, việc sử dụng chỉ đơn giản như thực hiện lệnh sau:
laravel new uploadApp
Bạn sẽ thấy kết quả tương tự như sau:
Composer đang cài đặt tất cả các gói mà Laravel cần để hoạt động. Quá trình này có thể mất vài phút, vì vậy hãy kiên nhẫn. Sau khi hoàn tất, hãy chạy lệnh `ls -al` để xem những gói nào đã được cài đặt.
Dưới đây là bảng phân tích ngắn gọn về các thư mục trong một ứng dụng Laravel phổ biến:
- ứng dụng/ : Đây là thư mục nguồn chứa mã ứng dụng của chúng ta. Tất cả các bộ điều khiển, chính sách và mô hình đều nằm trong thư mục này.
- khởi động/ : Chứa tập lệnh khởi động ứng dụng và một vài tập tin bản đồ lớp.
- cấu hình/ : Chứa các tệp cấu hình của ứng dụng. Các tệp này thường không được chỉnh sửa trực tiếp mà thay vào đó dựa vào các giá trị được thiết lập trong tệp .env (môi trường) ở thư mục gốc của ứng dụng.
- cơ sở dữ liệu/ : Chứa các tệp cơ sở dữ liệu bao gồm các bản di chuyển, dữ liệu mẫu và các nhà máy thử nghiệm.
- công cộng/ : Thư mục công khai chứa các tài nguyên đã được biên dịch và, tất nhiên, một tệp index.php.
- tài nguyên/ : Chứa các nội dung giao diện người dùng như JavaCác tập tin kịch bản, tập tin ngôn ngữ, tập tin CSS/SASS và tất cả các mẫu được sử dụng trong ứng dụng (gọi là mẫu Blade).
- tuyến đường/ : Tất cả các tuyến đường trong ứng dụng đều nằm trong tệp này. Có một vài "phạm vi" tuyến đường khác nhau, nhưng phạm vi mà chúng ta sẽ tập trung vào là tệp web.php.
- kho/ : Tất cả các tệp bộ nhớ đệm tạm thời được ứng dụng sử dụng, các tệp phiên, các tập lệnh hiển thị đã biên dịch và các tệp nhật ký.
- kiểm tra/ : Chứa các tập tin kiểm thử cho ứng dụng, chẳng hạn như kiểm thử đơn vị và kiểm thử chức năng.
- người bán/ : Tất cả các gói phụ thuộc đã được cài đặt bằng Composer.
Giờ thì, chúng ta hãy xây dựng phần còn lại của ứng dụng và chạy nó bằng một lệnh artisan đặc biệt (để tiết kiệm thời gian cài đặt và cấu hình máy chủ web như Apache hoặc nginx). Tệp .env chứa tất cả các giá trị cấu hình mà các tệp trong thư mục /config sử dụng để cấu hình ứng dụng.
Thiết kế ứng dụng: Tóm tắt nhanh các yêu cầu của chúng tôi
Trong hướng dẫn Laravel trực tuyến này, chúng ta sẽ xây dựng một ứng dụng rất đơn giản chỉ thực hiện hai việc:
- xử lý tải lên tệp từ biểu mẫu web
- Hiển thị các tệp đã tải lên trước đó trên một trang khác.
Trong dự án này, ứng dụng của chúng ta sẽ chỉ cho phép ghi, nghĩa là người dùng chỉ có thể ghi tệp và xem danh sách các tệp mà họ đã tải lên. Ứng dụng này cực kỳ đơn giản nhưng sẽ là một bài thực hành tốt để bạn bắt đầu xây dựng kỹ năng và kiến thức về Laravel. Lưu ý rằng để ngắn gọn, chúng ta đã bỏ qua bất kỳ phần nào về mô hình cơ sở dữ liệu, di chuyển dữ liệu và xác thực, nhưng trong một ứng dụng thực tế, đây là những điều bổ sung mà bạn cần xem xét.
Dưới đây là danh sách các thành phần mà chúng ta sẽ cần để làm cho ứng dụng hoạt động như mong đợi:
- A tuyến đường Điều này sẽ cho phép thế giới bên ngoài (internet) sử dụng ứng dụng, cũng như chỉ định điểm cuối trỏ đến nơi chứa logic lưu tệp đã tải lên.
- A điều khiển Nó xử lý luồng yêu cầu-phản hồi.
- A mẫu Nó sẽ được sử dụng để hiển thị danh sách các tệp đã được tải lên trước đó và chính biểu mẫu tải lên.
- A yêu cầu Bộ điều khiển sẽ sử dụng thông tin đó để xác thực dữ liệu được truyền vào từ biểu mẫu web.
Tuyến đường là gì?
Trong Laravel, route về cơ bản là một endpoint được chỉ định bởi URI, hoạt động như một "con trỏ" đến một chức năng nào đó do ứng dụng cung cấp. Thông thường, một route chỉ đơn giản là trỏ đến một phương thức trên controller và cũng quy định các phương thức HTTP nào có thể truy cập URI đó. Route không phải lúc nào cũng là một phương thức của controller; nó cũng có thể chỉ đơn giản là chuyển quyền thực thi ứng dụng cho một Closure hoặc hàm ẩn danh được định nghĩa.
Tại sao cần sử dụng tuyến đường?
Các tuyến đường được lưu trữ bên trong các tệp trong thư mục /routes bên trong thư mục gốc của dự án. Theo mặc định, có một số tệp khác nhau tương ứng với các "mặt" khác nhau của ứng dụng ("mặt" xuất phát từ phương pháp kiến trúc lục giác). Chúng bao gồm:
- web.php: các tuyến đường dựa trên "trình duyệt" hướng ra bên ngoài. Đây là những tuyến đường phổ biến nhất và là những tuyến đường mà trình duyệt web truy cập. Chúng chạy qua nhóm phần mềm trung gian web và cũng chứa các tiện ích cho... Bảo vệ CSRF (giúp phòng chống các cuộc tấn công độc hại dựa trên biểu mẫu) và thường chứa một mức độ "trạng thái" nhất định (ý chúng tôi là chúng sử dụng các phiên).
- api.php: các tuyến đường tương ứng với một nhóm API và do đó có middleware API được bật theo mặc định. Các tuyến đường này không có trạng thái và không có phiên hoặc bộ nhớ giữa các yêu cầu (một yêu cầu không chia sẻ dữ liệu hoặc bộ nhớ với bất kỳ yêu cầu nào khác; mỗi yêu cầu đều tự đóng gói).
- console.php: Các tuyến đường này tương ứng với các lệnh Artisan tùy chỉnh mà bạn đã tạo cho ứng dụng của mình.
- channels.php: đăng ký các tuyến đường để phát sóng sự kiện.
Tệp quan trọng cần quan tâm lúc này là tệp dành riêng cho trình duyệt, web.php. Đã có một tuyến đường được định nghĩa mặc định, đó là tuyến đường bạn truy cập ngay khi điều hướng đến thư mục gốc của ứng dụng web (thư mục gốc nằm trong thư mục public). Chúng ta sẽ cần ba tuyến đường khác nhau để ứng dụng tải lên của chúng ta hoạt động:
- /upload: đây sẽ là URI của trang chính hiển thị biểu mẫu web của chúng tôi để tải lên tập tin.
- /process: đây là nơi biểu mẫu nằm tại URI /upload sẽ gửi dữ liệu đã nộp của biểu mẫu đến (phần “hành động” của biểu mẫu).
- /list: lệnh này sẽ liệt kê tất cả các tệp đã được tải lên trang web.
Lưu ý: Điểm cuối /list có thể không cần thiết nếu chúng ta muốn đặt tất cả logic hiển thị biểu mẫu tải lên và danh sách tệp trên cùng một trang; tuy nhiên, hiện tại chúng ta vẫn giữ chúng tách biệt để làm rõ thêm vấn đề đang được thảo luận.
//inside routes/web.php
Route::get('/upload', 'UploadController@upload')->name('upload');
Route::get('/download', 'UploadController@download')->name('download');
Route::post('/process', 'UploadController@process')->name('process');
Route::get('/list', 'UploadController@list')->name('list');
Trong hướng dẫn về framework Laravel này, đối với mỗi tuyến đường mong muốn, chúng ta sẽ liệt kê rõ ràng trong tệp routes web.php bằng cách sử dụng một trong các phương thức yêu cầu HTTP cụ thể có sẵn (get(), post(), put(), delete(), patch() hoặc options()). Để biết chi tiết về từng phương thức, hãy xem phần tiếp theo. điều này Các phương thức này chỉ định những động từ HTTP nào được phép truy cập vào tuyến đường cụ thể đó. Nếu bạn cần một tuyến đường có thể chấp nhận nhiều hơn một động từ HTTP (điều này có thể xảy ra nếu bạn sử dụng một trang duy nhất để vừa hiển thị dữ liệu ban đầu vừa gửi dữ liệu biểu mẫu), bạn có thể sử dụng phương thức Route::any().
Đối số thứ hai của cả hai phương thức Route::get() và Route::post() (và bất kỳ phương thức nào khác liên quan đến động từ HTTP trên facade Route) là tên của một controller cụ thể và phương thức nằm bên trong controller đó sẽ được thực thi khi truy cập điểm cuối của route với yêu cầu HTTP được cho phép (GET, POST, PATCH, v.v.). Chúng tôi đang sử dụng UploadController cho tất cả các route và đã chỉ định chúng theo cách sau:
Phương thức cuối cùng mà chúng ta gọi trên mỗi route là hàm `name()`, hàm này chấp nhận một chuỗi ký tự làm đối số và được sử dụng để "gắn thẻ" cho một route cụ thể bằng một cái tên dễ nhớ (trong trường hợp của chúng ta là upload, process và list). Có vẻ như việc đặt tên riêng cho mỗi route không phải là một tính năng tuyệt vời khi... URL Tên gọi hoàn toàn giống nhau, nhưng nó thực sự hữu ích khi bạn có một đường dẫn cụ thể như /users/profile/dashboard/config, mà sẽ dễ nhớ hơn nếu là profile-admin hoặc user-config.
Một vài lưu ý về mặt tiền:
- Các Facade cung cấp một giao diện "tĩnh" cho các lớp có sẵn trong bộ chứa dịch vụ của ứng dụng.
- Chúng cung cấp một cú pháp ngắn gọn, dễ nhớ cho phép bạn sử dụng các tính năng của Laravel mà không cần nhớ những tên lớp dài dòng phải được chèn hoặc cấu hình thủ công.
Trong các định nghĩa tuyến đường ở trên, chúng ta sử dụng facade Route thay vì tự tạo một đối tượng Illuminate/Routing/Router mới và gọi các phương thức tương ứng trên đối tượng đó. Đây chỉ là một cách viết tắt giúp tiết kiệm thời gian.pingFacade được sử dụng rộng rãi trong toàn bộ framework Laravel; bạn có thể và nên làm quen hơn với chúng. Tài liệu về Facade có thể được tìm thấy tại đây. đây.
Bộ điều khiển là gì?
Controller là “C” trong kiến trúc “MVC” (Model-View-Controller), là kiến trúc mà Laravel dựa trên. Công việc của controller có thể được tóm gọn trong định nghĩa đơn giản này: Nó nhận yêu cầu từ máy khách và trả về phản hồi cho máy khách. Đây là định nghĩa cơ bản nhất và cũng là yêu cầu tối thiểu của bất kỳ bộ điều khiển nào. Những gì nó thực hiện giữa hai điều đó thường được coi là "hành động" của bộ điều khiển (hoặc "việc triển khai tuyến đường"). Nó hoạt động như điểm truy cập thứ hai vào ứng dụng (điểm đầu tiên là yêu cầu) dành cho máy khách, người gửi tải trọng yêu cầu (mà chúng ta sẽ đề cập tiếp theo) đến ứng dụng, mong đợi một loại phản hồi nào đó (dưới dạng trang thành công, chuyển hướng, trang lỗi hoặc bất kỳ loại phản hồi HTTP nào khác).
Về cơ bản, bộ điều khiển thực hiện chức năng tương tự như định nghĩa tuyến đường với một hàm ẩn danh được đặt làm "hành động" khi tuyến đường đó được gọi. Sự khác biệt là bộ điều khiển tuân thủ tốt nguyên tắc phân tách các mối quan tâm, trong khi tuyến đường được định nghĩa trực tiếp trong mã thực tế. URL Định nghĩa này về cơ bản có nghĩa là chúng ta đang liên kết URI được gán cho tuyến đường với phần triển khai của tuyến đường, hay đoạn mã được thực thi khi tuyến đường đó được truy cập.
Ví dụ, hai đoạn mã sau sẽ đạt được mục đích giống nhau:
Ví dụ #1: Định nghĩa và triển khai tuyến đường bên trong một lệnh gọi phương thức duy nhất (trong tệp tuyến đường web.php)
//inside routes/web.php
<?php
Route::get('/hello-world', function(Request $request) {
$name = $request->name;
return response()->make("<h1>Hello World! This is ".$name, 200);
});
Ví dụ #2: Định nghĩa của tuyến đường nằm trong routes/web.php, nhưng phần triển khai của nó nằm trong lớp /app/Http/Controllers/HelloWorldController.
//inside routes/web.php
<?php
Route::get('/hello-world', 'HelloWorldController@index')->name('hello-world');
------------------------------------------------------------------------------------
//inside app/Http/Controllers/HelloWorldController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HelloWorldController extends Controller
{
public function index(Request $request)
{
$name = $request->name;
return response()->make("<h1>Hello World! This is ".$name, 200);
}
}
Mặc dù ví dụ Laravel #2 có vẻ phức tạp hơn nhiều (thực ra không phải vậy, chỉ cần thêm một chút mã), hãy xem những lợi ích mà chúng ta đạt được bằng cách đặt logic xử lý cho tuyến đường "hello-world" bên trong một controller thay vì sử dụng định nghĩa tuyến đường dưới dạng hàm callback:
- Hệ thống logic của chúng ta được tách biệt rõ ràng thành một lớp riêng (tách biệt các mối quan tâm).
- Bộ điều khiển của chúng ta được thiết lập để có thể mở rộng sau này nếu cần thêm các chức năng khác. Ví dụ, nếu muốn thêm tính năng "tạm biệt thế giới", chúng ta sẽ đổi tên bộ điều khiển thành "HelloController" tổng quát hơn, sau đó định nghĩa hai phương thức riêng biệt. xin chào() và tạm biệt(). Chúng ta cũng cần xác định hai tuyến đường riêng biệt để ánh xạ /Xin chào và / Tạm biệt Các URI trỏ đến phương thức thích hợp trên bộ điều khiển. Điều này tốt hơn so với việc làm cho tệp định tuyến trở nên cồng kềnh với mỗi phần triển khai của tuyến đường được định nghĩa dưới dạng các hàm gọi lại.
- Laravel có khả năng tích hợp để lưu trữ tất cả các định nghĩa tuyến đường trong ứng dụng để tăng tốc thời gian tìm tuyến đường nhất định (tăng hiệu suất ứng dụng); Tuy nhiên, Bạn chỉ có thể tận dụng được điều đó nếu tất cả các tuyến đường được định nghĩa bên trong ứng dụng đều được cấu hình bằng cách sử dụng bản đồ dành riêng cho bộ điều khiển.ping(xem Ví dụ #2 ở trên).
Hãy chạy lệnh này để tạo bộ điều khiển mới cho chúng ta.
// ...inside the project's root directory: php artisan make:controller UploadController
Về cơ bản, lệnh này tạo ra một đoạn mã giả cho bộ điều khiển có tên “UploadController” bên trong thư mục bộ điều khiển chính tại /app/Http/Controllers/UploadController.php. Bạn có thể mở tệp đó ra và xem. Nó rất đơn giản vì chỉ là một phiên bản giả lập của bộ điều khiển, với đường dẫn không gian tên chính xác và các lớp cần thiết mà nó kế thừa.
Tạo yêu cầu
Trước khi tiếp tục hướng dẫn PHP Laravel này và thực hiện một vài thay đổi đối với đoạn mã mẫu được tạo ra của UploadController, sẽ hợp lý hơn nếu chúng ta tạo lớp yêu cầu trước. Điều này là bởi vì phương thức điều khiển xử lý yêu cầu phải khai báo kiểu dữ liệu của đối tượng yêu cầu trong chữ ký của nó, cho phép nó tự động xác thực dữ liệu biểu mẫu đến (như đã được chỉ định trong phương thức rules(); chi tiết hơn sẽ được đề cập sau). Bây giờ, hãy sử dụng lại lệnh artisan để tạo đoạn mã mẫu yêu cầu của chúng ta:
php artisan make:request UploadFileRequest
Lệnh này sẽ tạo một tệp có tên UploadFileRequest bên trong thư mục app/Http/Requests/UploadFileRequest. Hãy mở tệp đó ra và xem nội dung. Bạn sẽ thấy nó rất đơn giản, chỉ chứa hai phương thức là authorize() và rules().
Tạo logic xác thực
Hãy chỉnh sửa đoạn mã yêu cầu (request stub) để đáp ứng nhu cầu của ứng dụng. Chỉnh sửa tệp sao cho nó trông như thế này:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UploadFileRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'fileName' => 'required|string',
'userFile' => 'required|file'
];
}
}
Không có nhiều thay đổi, nhưng hãy lưu ý rằng phương thức `authorize()` giờ đây trả về `true` thay vì `false`. Phương thức này quyết định xem có cho phép yêu cầu đi vào ứng dụng hay không. Nếu được đặt thành `false`, nó sẽ ngăn yêu cầu vào hệ thống. Đây sẽ là một vị trí rất tiện dụng để đặt bất kỳ kiểm tra quyền truy cập nào đối với người dùng hoặc bất kỳ logic nào khác có thể quyết định xem yêu cầu có thể chuyển tiếp đến bộ điều khiển hay không. Hiện tại, chúng ta chỉ trả về `true` ở đây để cho phép mọi thứ sử dụng yêu cầu.
Phương pháp còn lại, rules(), là nơi mà tất cả sự kỳ diệu được phát huy liên quan đến việc xác thực. Ý tưởng rất đơn giản: trả về một mảng chứa một tập hợp các quy tắc có dạng:
'formFieldName' => 'constraints this field has separated by pipe characters (|)'
Có nhiều ràng buộc xác thực khác nhau được Laravel hỗ trợ ngay từ đầu. Để biết danh sách đầy đủ, hãy xem tài liệu trực tuyến đâyĐối với ứng dụng tải lên của chúng ta, sẽ có hai trường được truyền vào thông qua yêu cầu POST từ một biểu mẫu ở phía giao diện người dùng. Tham số `fileName` phải được bao gồm trong phần thân biểu mẫu (tức là bắt buộc) và được sử dụng làm tên tệp mà chúng ta sẽ lưu trữ tệp trong bộ nhớ (việc này được thực hiện trong bộ điều khiển; chúng ta sẽ đề cập đến nó sau). Chúng ta cũng chỉ định rằng tên tệp phải là một chuỗi bằng cách thêm ký tự dấu gạch dọc (|) và từ 'string'. Các ràng buộc luôn được phân tách bằng dấu gạch dọc, cho phép bạn chỉ định bất kỳ tiêu chí bổ sung nào cho trường đã cho trong một dòng duy nhất.
Tham số thứ hai, userFile, là tệp thực tế mà người dùng tải lên từ một biểu mẫu trên trang web. userFile cũng là tham số bắt buộc. phải là một tập tin. Lưu ý: Nếu chúng ta mong đợi tệp được tải lên là hình ảnh, thì chúng ta sẽ sử dụng ràng buộc hình ảnh, điều này sẽ giới hạn các loại tệp được chấp nhận chỉ còn một trong các loại hình ảnh phổ biến (jpeg, png, bmp, gif hoặc svg). Vì chúng ta muốn cho phép người dùng tải lên bất kỳ loại tệp nào, nên chúng ta sẽ chỉ sử dụng ràng buộc xác thực tệp.
Về cơ bản, đối tượng yêu cầu chỉ có vậy. Nhiệm vụ chính của nó là lưu trữ tập hợp các tiêu chí (ràng buộc) mà các tham số trong phần thân của biểu mẫu phải đáp ứng để có thể tiếp tục xử lý trong ứng dụng. Một điều cần lưu ý nữa là hai trường này (userFile và fileName) cũng phải được chỉ định trong mã HTML dưới dạng các trường nhập liệu (với tên trường tương ứng với tên trong đối tượng yêu cầu).
Có thể bạn đang thắc mắc: điều này định nghĩa các đặc điểm mà một yêu cầu biểu mẫu nên chứa, nhưng việc kiểm tra thực tế các ràng buộc này được thực hiện ở đâu? Chúng ta sẽ tìm hiểu điều đó ở phần tiếp theo.
Sửa đổi bộ điều khiển
Mở app/Http/Controllers/UploadController và thực hiện những thay đổi sau:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use App\Http\Requests\UploadFileRequest; //our new request class
use Illuminate\Support\Facades\Storage;
class UploadController extends Controller
{
/**
* This is the method that will simply list all the files uploaded by name and provide a
* link to each one so they may be downloaded
*
* @param $request : A standard form request object
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws BindingResolutionException
*/
public function list(Request $request)
{
$uploads = Storage::allFiles('uploads');
return view('list', ['files' => $uploads]);
}
/**
* @param $file
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
* @throws BindingResolutionException
*/
public function download($file)
{
return response()->download(storage_path('app/'.$file));
}
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws BindingResolutionException
*/
public function upload()
{
return view('upload');
}
/**
* This method will handle the file uploads. Notice that the parameter's typehint
* is the exact request class we generated in the last step. There is a reason for this!
*
* @param $request : The special form request for our upload application
* @return array|\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null
* @throws BindingResolutionException
*/
public function process(UploadFileRequest $request)
{
//At this point, the parameters passed into the $request (from form) are
//valid--they satisfy each of the conditions inside the rules() method
$filename = $request->fileName; //parameters have already been validated
$file = $request->file('userFile'); //so we don't need any additional isset()
$extension = $file->getClientOriginalExtension(); //grab the file extension
$saveAs = $filename . "." . $extension; //filename to save file under
$file->storeAs('uploads', $saveAs, 'local'); //save the file to local folder
return response()->json(['success' => true]); //return a success message
}
}
Vì vậy, đây là một cách tiếp cận khá đơn giản để lưu các tệp đã tải lên vào ổ đĩa. Dưới đây là phân tích chi tiết về phương thức process() ở trên:
- Hãy khai báo kiểu dữ liệu cho lớp yêu cầu trong phương thức điều khiển thực hiện chức năng chính để chúng ta có thể tự động xác thực dữ liệu đến.
- Lấy tập tin từ đối tượng yêu cầu (đã được xác thực) bên trong phương thức điều khiển.
- Lấy tên tệp từ yêu cầu.
- Tạo tên tệp cuối cùng sẽ được sử dụng để lưu tệp bên dưới. Phương thức getClientOriginalExtension() chỉ cần lấy phần mở rộng gốc của tệp đã tải lên.
- Lưu trữ tệp vào hệ thống tệp cục bộ bằng phương thức storeAs() của nó, chuyển vào đường dẫn được đặt tên bên trong thư mục /storage làm đối số thứ nhất và tên tệp để lưu nó làm đối số thứ hai.
- Trả về phản hồi JSON cho biết yêu cầu đã thành công.
Mẫu lưỡi dao
Phần quan trọng cuối cùng của câu đố này là mẫu lưỡi dao, nó sẽ chứa tất cả HTML, CSS và JavaĐây là đoạn mã cho ứng dụng đơn giản của chúng ta. Chúng ta sẽ giải thích nó sau.
<body>
<h1>Upload a file</h1>
<form id="uploadForm" name="uploadForm" action="{{route('process')}}" enctype="multipart/form-data">
@csrf
<label for="fileName">File Name:</label>
<input type="text" name="fileName" id="fileName" required /><br />
<label for="userFile">Select a File</label>
<input type="file" name="userFile" id="userFile" required />
<button type="submit" name="submit">Submit</button>
</form>
<h2 id="success" style="color:green;display:none">Successfully uploaded file</h2>
<h2 id="error" style="color:red;display:none">Error Submitting File</h2>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$('#uploadForm').on('submit', function(e) {
e.preventDefault();
var form = $(this);
var url = form.attr('action');
$.ajax({
url: url,
type: "POST",
data: new FormData(this),
processData: false,
contentType: false,
dataType: "JSON",
success: function(data) {
$("#fileName").val("");
$("#userFile").val("");
}
}).done(function() {
$('#success').css('display', 'block');
window.setTimeout(()=>($("#success").css('display', 'none')), 5000);
}).fail(function() {
$('#error').css('display', 'block');
window.setTimeout(()=>($("#error").css('display', 'none')), 5000);
});
});
</script>
</body>
</html>
Đây là những gì chúng tôi /tải lên trang trông giống như:
Đây là một ví dụ rất điển hình về tệp phiến chứa biểu mẫu HTML và JavaĐoạn mã/jQuery để thêm chức năng bất đồng bộ (để trang không cần tải lại). Có một đoạn mã cơ bản. Thẻ không có thuộc tính `method` (chúng ta sẽ giải thích điều này ngay sau đây) và có một thuộc tính `action` khá lạ với giá trị `{{route('process')}}`. Trong Blade, đây được gọi là một thẻ `<route>`. Chỉ thị. Chỉ thị (directive) chỉ là một tên gọi hoa mỹ cho hàm; chúng là các hàm đặc thù của mẫu Blade, thực hiện các thao tác khác nhau thường gặp trong việc xây dựng trang web và ứng dụng web. Để hiểu rõ hơn về tất cả những điều hữu ích mà Blade có thể làm, hãy xem tài liệu. đâyTrong trường hợp trên, chúng ta đang sử dụng chỉ thị route để tạo ra một URL để chúng tôi gửi biểu mẫu.
Hãy nhớ rằng chúng ta đã định nghĩa các tuyến đường trước đó trong ứng dụng bên trong tệp web.php, chỉ định một tên dễ nhớ cho mỗi tuyến đường. Chỉ thị {{route()}} chấp nhận tên của một tuyến đường, tìm kiếm nó trong danh sách các tuyến đường được lưu vào bộ nhớ cache nội bộ và tạo ra một tuyến đường đầy đủ. URL dựa trên định nghĩa của tuyến đường đó trong tệp web.php. Trong trường hợp đầu tiên này, chúng ta chỉ định rằng chúng ta muốn biểu mẫu gửi dữ liệu đã gửi của nó đến /process. URL của ứng dụng của chúng tôi, được định nghĩa là một POST tuyến đường.
Điều tiếp theo bạn có thể nhận thấy là thẻ `@csrf` ngay bên dưới thẻ mở `<form>`. Trong Blade, thẻ này tạo ra một tham số `_token` trên biểu mẫu, tham số này sẽ được kiểm tra bên trong ứng dụng trước khi dữ liệu biểu mẫu được phép xử lý. Điều này đảm bảo rằng dữ liệu bên trong biểu mẫu có nguồn gốc hợp lệ và ngăn chặn các cuộc tấn công giả mạo yêu cầu liên trang (CSRF). Để biết thêm thông tin về vấn đề này, hãy xem phần tiếp theo. tài liệu.
Sau đó, chúng ta định nghĩa biểu mẫu của mình như bình thường; tuy nhiên, cần lưu ý rằng tên của các tham số biểu mẫu, userFile và fileName, là... hoàn toàn giống nhau như đã được định nghĩa bên trong đối tượng yêu cầu của chúng ta. Nếu chúng ta quên thêm dữ liệu đầu vào cho một tham số nhất định đã được định nghĩa trong đối tượng yêu cầu (hoặc viết sai chính tả), yêu cầu sẽ thất bại và một lỗi sẽ được trả về, ngăn không cho yêu cầu biểu mẫu ban đầu được gọi đến phương thức điều khiển nằm tại UploadController@process.
Hãy thử ngay và gửi một vài tập tin vào ứng dụng bằng biểu mẫu này. Sau đó, hãy truy cập vào... /danh sách để xem nội dung của thư mục tải lên, với các tệp bạn đã tải lên được liệt kê trong bảng:
The Bigger Picture
Hãy cùng nhìn lại những gì chúng ta đã làm trong hướng dẫn Laravel này.
Sơ đồ này mô tả ứng dụng ở trạng thái hiện tại (không bao gồm các chi tiết cấp cao):
Bạn nên nhớ rằng đối tượng yêu cầu mà chúng ta đã tạo ở đầu hướng dẫn Laravel này phải có các tham số được định nghĩa trong phương thức `rules` giống như các tham số trên biểu mẫu trong mẫu Blade (nếu không, hãy đọc lại phần “Tạo logic xác thực”). Người dùng nhập biểu mẫu trên một trang web được hiển thị thông qua công cụ mẫu Blade và gửi biểu mẫu. Mã jQuery của mẫu ở cuối sẽ ngăn chặn việc gửi mặc định (điều này sẽ tự động chuyển hướng đến một trang riêng biệt), tạo một yêu cầu Ajax, tải yêu cầu với dữ liệu biểu mẫu và tệp đã tải lên, và gửi toàn bộ vào lớp đầu tiên của ứng dụng: yêu cầu.
Đối tượng yêu cầu được điền dữ liệu bằng cách liên kết các tham số bên trong phương thức `rules()` với các tham số của biểu mẫu đã gửi, sau đó xác thực dữ liệu theo từng quy tắc được chỉ định. Nếu tất cả các quy tắc được thỏa mãn, yêu cầu sẽ được chuyển tiếp đến phương thức điều khiển tương ứng với các giá trị được định nghĩa trong tệp định tuyến `web.php`. Trong trường hợp này, phương thức `process()` của `UploadController` thực hiện công việc. Khi đến được bộ điều khiển, chúng ta đã biết rằng yêu cầu đã vượt qua quá trình xác thực, vì vậy chúng ta không cần phải kiểm tra lại xem tên tệp được cung cấp có thực sự là một chuỗi hay tham số `userFile` thực sự chứa một loại tệp nào đó. Chúng ta có thể tiếp tục như bình thường.
Phương thức điều khiển sau đó lấy các tham số đã được xác thực từ đối tượng yêu cầu, tạo tên tệp đầy đủ bằng cách nối tham số fileName được truyền vào với phần mở rộng gốc của userFile, lưu tệp vào một thư mục trong ứng dụng của chúng ta, sau đó trả về phản hồi được mã hóa JSON đơn giản để xác minh rằng yêu cầu đã thành công. Phản hồi được nhận bởi logic jQuery, thực hiện thêm một vài tác vụ liên quan đến giao diện người dùng như hiển thị thông báo thành công (hoặc lỗi) trong 5 giây, sau đó ẩn nó đi, cũng như xóa các mục nhập biểu mẫu trước đó. Điều này nhằm đảm bảo người dùng biết chắc chắn rằng yêu cầu đã thành công và có thể tải lên một tệp khác nếu muốn.
Ngoài ra, hãy chú ý đến sơ đồ ở trên về vị trí phân định giữa máy khách và máy chủ. Khái niệm này vô cùng quan trọng để bạn hiểu và sẽ giúp bạn giải quyết các vấn đề có thể gặp phải trong tương lai khi xử lý nhiều yêu cầu bất đồng bộ cùng một lúc. Sự phân tách nằm ngay tại ranh giới của đối tượng yêu cầu. Bản thân đối tượng yêu cầu có thể được coi là "cổng" dẫn đến phần còn lại của ứng dụng. Nó thực hiện việc xác thực và đăng ký ban đầu các giá trị biểu mẫu được truyền từ trình duyệt web. Nếu chúng được coi là hợp lệ, thì nó sẽ tiếp tục đến bộ điều khiển. Mọi thứ trước đó đều nằm ở phía giao diện người dùng ("máy khách" theo nghĩa đen là "trên máy tính của người dùng"). Phản hồi được trả về từ ứng dụng trở lại phía máy khách, nơi mã jQuery của chúng ta kiên nhẫn lắng nghe sự xuất hiện của nó và thực hiện một vài tác vụ giao diện người dùng đơn giản sau khi nhận được.
Chúng tôi cũng đã giải đáp nhiều câu hỏi thường gặp quan trọng. Câu hỏi phỏng vấn liên quan đến Laravel và PHP dành cho sinh viên mới ra trường cũng như những ứng viên có kinh nghiệm để có được công việc phù hợp.








