梦入琼楼寒有月,行过石树冻无烟

📖 earlier posts 📖

Laravel 请求与Cookie

在目前,请求已经覆盖了几乎上所有的站点,当你在提交表单的时候,我们通常都会成此次操作为一次表单请求,而表单请求通常别运用到了表单的填写、用户的注册、文章的发布等一系列场景之中,本文将会带读者进入到Laravel请求的实现过程。

URL请求


通常我们最为常用的是通过url进行请求,比如我们访问“https://pv.zsun.org.cn/loophole-data/ZSUN-2020-71”则会请求该站点的服务器,由服务器进行响应,我们可以通过控制器+路由的方式进行实现:

获取url

TestController

在编写控制器之前我们需要进行创建,创建控制器的方法我们可以通过artisan进行创建,创建语法为:

php artisan make:controller TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function __invoke(Request $request) {
$url = $request -> url();
echo 'This request url be:'.$url;
}
}

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

Route::get('/url' ,'TestController');

获取 id


在实际的开发过程中,我们会遇到很多次的获取用户跳转id的类似需求,而实现这种需求我们也可从第一个例子中慢慢演变:

web.php

1
2
3
4
5
6
7
Route::get('/input/{id}', 'TestController@up');
```
#### TestController
```php
public function up(Request $request, $id) {
echo $id;
}

路由获取 id


当然慢慢的你会觉得还需要单独创建一个控制器(Controller)有点且非常的麻烦,那你可以使用下面这种直接在路由中开写的:

web.php

1
2
3
Route::get('/input/{id}', function (Request $request, $id) {
echo $id;
});

表单请求

表单请求几乎上是项目开发中最为常用的一种,通常运用在注册、登录、发布文章等处用的最多,本文我们将会为读者编写一个较为简单的表单请求与控制器获取的操作:

获取信息

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {
$name = $request->input('username');
echo $name;
}
}

/resources/views/input.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<title>This is be Input up</title>
</head>
<body>
<form action="/user/name" method="post">
<input type="hidden" name="_token" value="<?php echo csrf_token()?>">
Username:<input type="text" name="username" />&nbsp;
<input type="submit" value="up">
</form>
</body>
</html>

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

Route::get('/input' ,function () {
return view('input');
});
Route::post('/user/name', array('uses'=>'TestController@store'));

表单检测

is (表单url)


当然,Laravel还为我们提供了丰富的表单检测的方法,分别为检测表单提交方法,比如post/get的、也有检测表单提交url的,下面我们将会分别进行演示:

TestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {
$name = $request->input('username');
if ($request->is('user/name')) {
echo "提交正确";
return;
} else {
echo "提交错误";
return;
}
}
}

这个我们主要用于检测表单提交后的目录,如果不是该控制器中所指定的目录将会出现提交错误的字样。

isMethod (检测提交方法)

TestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {
$name = $request->input('username');
if ($request->isMethod('post')) {
echo "提交正确";
return;
} else {
echo "提交错误";
return;
}
}
}

在Laravel项目中,为我们提供了isMethod方法来用于判断表单的提交方法,以上例子是通过Post进行提交,但是如果使用get形式提交的话将会出现提交错误的字样。

boolean (布尔)

在Laravel项目中,布尔的提交方式较为不同,当你提交true的时候,那么会回显为1,当你提交1的时候,回显的还将是1

TestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {
$name = $request->boolean('username');
echo $name;
}
}

has


在Laravel项目中has主要用于检测表单是否存在,但是翻译后他会显示“has方法来确定请求中是否存在该值”,那么我们可以写一个检测表单是否存在的:

TestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {

if ($request->has('sss')) {
echo "yes";
} else {
echo "no";
}
}
}

在控制器中,我们在has方法后面写了一个名为”sss“的前端表单,如果存在即返回yes,不存在则返回no,那么在前端页面中,我们并不存在name为sss的表单即input,所以返回了no.

运算符


在实际的开发过程中我们总需要检测一些非法表单的提交,如!×#!@×#一些乱码或空白表单的问题,在Laravel之中与其他语言一样,都是支持运算符的,我们可以通过运算符进行判断该数据是否在“黑名单之中”

TestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function store(Request $request) {
$name = $request->input('username');
if ($name == '1') {
echo "yes";
} else {
echo "no";
}
}
}

在上述的code中,我们在TestController控制器中加入了一个运算符==来判断$name的函数是否存在等于1的情况,如果提交数据等于1则返回yes,否则返回no。


Cookie是在项目开发过程中较为不常用的一种方式,但这种技术运用在会话中较为常用,如钟山计算机端口安全联合众测平台中就是用Cookie技术来达到会话在一定时间内不会过期的问题:

创建cookie

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace App\Http\Controllers;

use http\Cookie;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class TestController extends Controller
{
public function store(Request $request,Response $response) {
// 创建cookie
$response = new Response();
$response->withCookie(cookie('name', 'value'));

// 获取cookie
$value = $request->cookie('name');
echo $value."<br>";
return $response;
}
}


withCookie中,如果你是使用PhpStort的读者,肯定会明白意思,因为集成开发环境会在前面分别进行标注。在本文演示中,我们并没有设置其Cookie的过期时间,读者如果在项目或学习过程有需要的话,可以加入第三项,为其cookie设置时间。

获取cookie


在Laravel项目中,我们有两种凡是来获取和访问cookie值,可分别使用请求(request)或使用CookieFacade来访问:

Request

1
2
3
4
public function store(Request $request) {
$value = $request->cookie('laravel_session');
echo $value."<br>";
}

CookieFacade

1
2
3
4
public function store(Request $request) {
$values = \Illuminate\Support\Facades\Cookie::get('laravel_session');
echo $values;
}

Laravel 控制器

控制器的存在主要用于替代路由文件中以闭包形式所有的请求处理逻辑,可以使用控制器来组织这些行为,在MVC框架之中,分为业务模型(M)、用户视图(V)、控制器(C),使用MVC的目的是将M和V的实现代码分离,控制器用于确保业务模型以及用户视图的同步,一旦业务模型进行更改,那么用户视图也会随着更改。

控制器主要存放在app/Http/Controllers/目录下,默认情况下并不会生成,需要使用命令php artisan make:controller TestController进行创建,在此会有一个命名潜规则是“作用+Controller”,如本次的控制器作用是测试则命名方式可为“TestController”即可,之后会在app/Http/Controller目录内生成该类,内容如下:

数据传递


通常我们需要将参数传递到控制器中,在Laravel之中,我们可以通过控制器进行传递,本次我们将实现一个传递id的效果:

命名空间(俗称 “路由绑定”)

在定义路由时,我们通常不需要写入完整的控制器名称,这是因为ProuteServiceProvider几乎将所有的路由文件加载到了包含名称空间的路由组中。比如一个控制器类的完整空间为namespace App\Http\Controllers;,此时我们可以在路由器中写成:

Route::get(‘/id/{id}’, ‘TestController@index’);

是可以找到TestController控制器的,当然如果你有相关的项目需要或自身的习惯也可以写完整的路径,浙江取决于你。

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class TestController extends Controller
{
public function index($id) {
echo "My is be ID: ".$id;
}
}

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

// 这里我们调用的TestController控制器的@index方法
Route::get('/id/{id}', 'TestController@index');

单个行为控制器


单个行为控制器说的通俗且简单一点就是,该控制器只用于处理你这一个请求,定义的方法也与普通的控制器有所不同,最为不同的一个点是在方法前面加了两个__,即__invoke函数:

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class TestController extends Controller
{
public function __invoke($id) {
echo "My is be ID: ".$id;
}
}

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

Route::get('/id/{id}', 'TestController');

视图控制器

与路由一样,控制器也拥有一个视图控制器,而定义方法与路由所相差无几,实现如下,在Laravel项目中,只需要在控制器中添加一个返回视图的方法以及配置路由即可:

TestController

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class TestController extends Controller
{
public function index() {
return view('welcome');
}
}

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

Route::get('/test', 'TestController@index');

之后通过访问locahost:8000/test回显的视图将是在resources/下的welcome.blade.php视图文件。

资源控制器(增删改查 “CURD”)

在Laravel中,资源控制器将经典的增删改查简化成了一行行控制器代码,Laravel为我们提供了一套约定的规则,这种规则可以方便我们的代码写的更加的完美且优雅,以下我们可以通过使用Artisan来生成一个资源控制器,使用的参数为--resource

php artisan make:controller PostController –resource

这与普通的控制器一样,会在``app\Http\Controllers```下创建一个名为PostController的控制器,且自动帮我们生成了CURD方法,我们可以通过对应请求在路由中进行绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}

/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}

/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}

/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
请求方式 Route FA 路由名称
GET /post 所有数据展现 index
GET /post/create 插入数据 create
POST /post/store 存储刚刚新提交的数据 store
GET /post/{id} 显示某个数据 show
GET /post/{id}/edit 修改某个数据 edit
PUT /post/{id} 更新数据库中某个资源 update
DELETE /post/{id} 删除某个数据 destory

如果在路由中使用该资源控制器也非常的简单,可以在web.php类中来绑定资源控制器即可:

Route::resource(‘post’, ‘PostController’);

实际开发过程中的伪造方法

在实际开发的过程中,我们会遇到很多问题,前端表单支持GET/POST方法但不支持PUT/DELETE的请求方式,所以我们在前端中需要使用一个Blade指令**@method**来使用伪造HTTP动作:

1
2
3
4
<form action="/post/update" method="POST">
@method('PUT')
……
</form>

指定资源路由

指定资源路由在官方文档中被命名为“部分资源路由”,这里我们以白名单与黑名单为例子让读者更加进一步理解:

1
2
3
4
5
6
7
8
9
10
11
12
// 使用所有
Route::resource('post', 'PostController');

// 白名单 -> Only 只有……
Route::resource('post', 'PostController')->only([
'index' //…… ‘index', 'show' 'create'
]);

// 黑名单 -> except 除了……以外
Route::resource('post', 'PostController')->except([
'create', 'update' // …… 'index'
]);

白名单(only)

白名单指only,中文译名为,顾名思义指这个处理器包含什么样的行为,在Laravel之中默认行为是所有。

1
2
3
4
// 白名单 -> Only 只有……
Route::resource('post', 'PostController')->only([
'index' //…… ‘index', 'show' 'create'
]);

黑名单 (except)

Laravel之中的except可以理解为是黑名单,但原意思是“除了……之外”,所以以下例子为除了create、update方法,PostController之中的资源路由我全要。

1
2
3
4
// 黑名单 -> except 除了……以外
Route::resource('post', 'PostController')->except([
'create', 'update' // …… 'index'
]);

命名资源路由

在资源控制器名称写入路由的时候,当处理需求较小的情况下还好,但一旦数据非常的庞大,我们除了对路由进行分组,也有一个命名资源路由的方法,只需要使用names即可:

1
2
3
Route::resource('post', 'PostController')->names([
'create' => 'post.create'
]);

资源路由参数

为了让前端变得更加美妙且更好的分辨,Laravel为我们提供了一种用于命名资源路由的方法parameters

1
2
3
Route::resource('post', 'PostController')->parameters([
'post' => 'test_post'
]);

之后将会生成/post/{post_test}的url构造。

Laravel 中间件

在Laravel之中,中间件提供了一种较为方便的机制来过滤应用程序的HTTP请求,如果学习过Spring security的读者肯定不陌生,假如Larvael有一个认证身份的中间件,如果未经过授权就可以访问不可访问的内容,则会被重定向至登录界面。
在Laravel之中不仅仅包含了身分验证的中间件,还自带了CSRF防护的中间件,而中间件所在的目录即在/app/Http/Middleware目录下,所以我们需要定义一个中间件:

php artisan make:middleware MiddleWare

在这里之中作者出现了一个潜规则的错误,在创建中间件的过程中应该使用 需求+中间件的潜规则,则按照潜规则来命名的话需要这样:IdMiddleware

之后我们会发现他Laravel会在app/Http/Middleware目录下创建一个MiddleWare.php类,在这个中间件中我们可以对其进行写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Http\Middleware;

use Closure;

class MiddleWare
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
echo "Is be Middleware";
return $next($request);

}
}

在中间件中,我们所定义了一个当当前id等于10的情况下,将会返回一个yes

注册中间件


在此之后我们需要去注册一个全局的中间件。全局中间件需要在app/Http/Kernel.php中进行。

全局注册

1
2
3
4
5
6
7
8
9
10
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
……
\App\Http\Middleware\MiddleWare::class,
],

全局注册即所有路由都将经过的中间件,我们可以在$middlewareGroups下进行添加之后访问localhost:8000即可查看中间件所输出的Hello,world!。

路由注册

1
2
3
4
5
6
7
8
9
10
11
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
……
'hey' => \App\Http\Middleware\MiddleWare::class,
];

在Kernel类中,我们注册了一个MiddleWare名为的中间件,其注册语法为:'id' => \App\Http\Middleware\MiddleWare::class,

控制器

路由注册长伴着控制器一起进行,通常在Laravel项目中控制器并不是默认存在的,需要使用如下命令进行生成:

php artisan make:controller TestController

之后Controller控制器将会存放在App\Http\Controllers目录下,并存在着一个TestController的类。

TestController
1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
public function index() {
echo "<br>Is be Controller";
}
}

web.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
return view('welcome');
});

// 使用路由器组进行绑定
Route::group(['middleware' => ['hey']], function () {
Route::get('test','TestController@index')->name('test');
});

Laravel 路由

Laravel路由与Spring boot的控制器相差无几,相信学过Spring boot的读者会感觉Laravel非常的和蔼可亲,甚至比Spring boot更好理解。通过阅读前面的Laravel的文件结构我们可以得知,在app/reutes/web.php文件中定义路由,在这里面的路由通常都会被分配给web中间件组,在不为人知的情况下,他还提供了会话状态和CSRF保护的作用

路由的定义


在Laravel中,为我们提供了一个简洁优雅的定义路由语法,为:

1
2
3
Route::get('/hey', function () {
return 'hello,world!';
});

视图路由

当然此时你觉得单纯的返回字符串已经完全满足不了需求了,这个时候我们可以在定义一个视图(view)路由,需要注意的视图路由通常存放在resources/view/目录下:

1
2
3
Route::get('/', function () {
return view('welcome');
});

这个时候如果你访问localhost:8000则会跳转至/reousces/view/welcome.blade.php文件所呈现的视图。

重定向路由(redirect)

重定向路由即访问$url后跳转至另外一个url,而不会产生任何的报错即称之为“重定向”,通俗了说就是你在你家开了房门,发现外面并不是自己的家就为重定向:

重定向到另一个视图

1
Route::redirect('/hey', '/');

即访问http://localhost:8000/hey,重定向到'/'所显示的视图```/resources/view/welcome.blade.php```。

重定向到上一个页面

1
2
3
Route::get('/hey', function () {
return redirect()->back();
});

在Laravel之中,我们也可通过Route::get的方式来进行重定向,而最终执行重定向的是return redirect,只不过第一种方法更加的简洁。

路由参数

路由参数通常是指用于传递的一些信息,主要分为两类,分别为必要参数以及一个可选参数,本文我们主要通过获取id以及名称来进行不同的演示:

必要参数

1
2
3
Route::get('id/{id}', function ($id) {
echo "我的ID是:".$id;
});

可通过访问localhost:8000/id/8012来访问自己的id,所返回的结果也一定是我的ID是:8012

可选参数

可选参数与必要参数的区别就是,可选参数允许你提交空值,之后所返回的不是404而是默认定义的字符串或数值。如通过必要参数时,你访问localhost:8000/id/则会返回404,但是如果使用可选参数将会返回默认的值,定义方法如下:

1
2
3
4
5
6
7
Route::get('user/{name?}', function ($name = null) {
return $name;
});

Route::get('user/{name?}', function ($name = 'test') {
return $name;
});

这样你如果访问localhost:8000/user/不会返回404,而是返回test信息。

路由约束

路由约束可分为正则表达式约束、全局约束两种方式,可以理解为使用正则表达式来约束单个路由,使用全局约束来约束全部路由:

正则表达式约束

使用正则表达式约束需要配合where来定义一个正则表达式用于约束该路由:

单个函数约束

1
2
3
Route::get('id/{id}', function ($id) {
echo "我的ID是:".$id;
})->where('id','[0-9]+');

多个函数约束

1
2
3
Route::get('user/{id}/{name}', function ($id, $name) {
echo "当前用户ID:".$id . ",名称是:" . $name;
})->where(['id' => '[0-9]+', 'name' => '[A-Za-z]+']);

此时如果你访问http://localhost:8000/user/1/test将会显示“当前用户ID:1,名称是:test”,但是如果不按照正则表达式约束则会出现404的错误,如http://localhost:8000/user/1s/test

全局约束

在Laravel项目中,全局约束由app/Providers/RouteServiceProvider.php所定义,具体为在19行左右之中:

1
2
3
4
5
6
7
8
9
10
11
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
// 定义id函数仅允许0-9的输入回显
Route::pattern('id','[0-9]+');
parent::boot();
}

routes/web.php文件内容如下:

1
2
3
Route::get('user/{id}', function ($id) {
echo "我的ID是:".$id;
});

之后通过http://localhost:8000/user/11s访问则会出现404错误,如按照全局约束文件内定义访问```http://localhost:8000/user/11```则会回显“我的ID是:11”数据。

路由命名

路由命名可以为指定的路由生成一个url或者重定向,可以通过name来指定路由名称:

1
2
3
4
5
6
7
Route::get('/test', function () {
return view('test');
});

Route::get('user/{id?}', function ($id = 1) {
echo "我的ID是:".$id;
})->name('user.id');

路由名称前缀

后续我们会有一个路由前缀,而为了简便开发,Laravel还提供了一个路由名称前缀,来方便我们与视图的对接:

1
2
3
4
5
6
7
8
9
10
11
Route::group([], function () {
Route::get('/test', function () {
return view('test');
});
Route::name('user.')->group(function () {
Route::get('user/{id?}', function ($id = 1) {
echo "ID is be:" .$id;
})->name('id');
});
……
});

当然我们这还加上了路由分组,来让代码的可读性和延伸扩展性进行了一系列的优化,而这个路由前缀的最后结果为user.id,我们可以继续。

test.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Laravel</title>

<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<body>
<a href="{{route('user.id', ['id' => 10])}}">go></a>
</body>
</head>
</html>

路由分组

在Laravel框架中,路由分组可以通过使用Route::group将不同的路由分别划分在一起,来让代码更加的简洁优雅:

1
2
3
4
5
6
7
8
9
Route::group([],function () {
Route::get('/test', function () {
return view('test');
});

Route::get('user/{id?}', function ($id = 1) {
echo "我的ID是:".$id;
})->name('user.id');
});

子域名路由

顾名思义即用于处理子域名的路由,如pv.zsun.org.cn就是一个子路由,本文仅仅用于演示语法,该语法并不具有可执行性,想实现的读者可通过配置服务器应用文件即可。

1
2
3
4
5
6
7
Route::domain('{er}.url.org.cn')->group(function () {
Route::get('user/{id}', function ($er, $id) {
// code
echo "当前子域名为:".$er;
echo "用户ID为:".$id;
});
});

域名前缀

1
2
3
4
5
6
Route::prefix('one')->group(function () {
Route::get('two', function () {
// 即 localhost:8000/one/two
echo "one/two";
});
});

域名前缀偶尔会让读者产生一丝的误会,实际上域名前缀指的是一个一个目录下包含着的一些文件,以这个为比喻可能更加方便读者的理解,如上述我们所写的域名前缀则意为:

one/下的/two,即可通过http://localhost:8000/one/two进行访问,当然我们也可以定义一个three:

1
2
3
4
5
6
7
8
9
Route::prefix('one')->group(function () {
Route::get('two', function () {
// 即 localhost:8000/one/two
echo "one/two";
});
Route::get('three', function () {
echo "one/three";
});
});

Laravel 项目配置与模式

项目配置

env

Laravel的项目配置与模式与Java or Java web差不多,可通过.env文件自来配置当前项目的环境,这个文件是在composer创建项目时自动进行创建的,其中.env下的文件都是自进行生成的,当然你也可以根据项目所需进行自定义,以下是.env文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:mHuJZujFK7vNFQAK+TqBNYGkw16feddY6Bf6oK8UUtc=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

config/database.php

相信很多读者都使用过原生态的php写web项目,连接数据库的语法都极具特色,在Laravel项目中,Laravel为我们提供了一个专门的数据库配置文件,我们只需要修改相关参数即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],

模式

维护模式 (down)


Laravel维护模式可以通过使用php artisan down进行开启,开启后如果再次访问则会出现503:暂停服务的字样

正常模式 (up)


当然,Laravel不仅仅支持维护模式,还支持一个正常模式,这个模式下则会显示正常的文件内信息,可通过php artisan up开启。

Laravel Redis&Command

Laravel 可以通过 Command 以及相关方法来讲 Redis 进行存储并映射到 MySQL 数据库中,通过 composer require predis/predis 命令来安装 Laravel Redis 的扩展,前提是在 PHP 具有 redis 扩展。

1
查看是否具有 Redis 的扩展我们可以通过 ```php -m``` 的命令来进行查看,如果没有我们可以通过集成环境或者直接到 pecl 所提供的 PHP 扩展下载站 [PECL](https://pecl.php.net/package/redis)中来进行下载,可以通过 ```php --verion``` 来查看当前的 PHP 类型和当前环境信息等。

按照官方文档的示例,在安装完 Redis 扩展后,我们可以在 .env 文件中修改 REDIS_PASSWORD 等配置,此外,也可以建立多个 Redis 链接,但前提是在 config/database.php 中进行一定的配置。

我们也可以在 config/database.php 中配置 Redis 的相关的账号信息,比如账号密码和 Key 名等,都可以在 redis 中进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
'redis' => [  

'client' => env('REDIS_CLIENT', 'phpredis'),

'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],

'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', 'redis'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '14'),
],

'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '15'),
],
],

之后,我们也可以在 app/Http/Controllers/ 中定义一个名为 RedisController.php 的控制器,引入 Illuminate\Support\Facades\Redis 扩展并作为 App\Http\Controllers\Controller 的延伸,定义两个基础的 Redis 存储方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php  

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Redis;

class RedisController
{
public function set() {
Redis::set('key','hello,redis!');
}

public function get() {
$name = Redis::get('key');
var_dump($name);
}

}

之后,为了使得方法的正常执行,我们还需要通过路由来定义,在 routes/web.php 中写入:

1
2
Route::get('/get', 'RedisController@get');  
Route::get('/set', 'RedisController@set');

最后,我们就可以通过 http://127.0.0.1:8000/sethttp://127.0.0.1:8000/get 来进行对 Redis 的 Set 和 Get 的操作。

同样的 Laravel Predis 支持了 Redis 的命令,我们可以通过阅读 Redis 官方文档Redis 速查表 来配合 Laravel 来进行实现对 Redis 的操作。

对于 hMset 类型的插入,我们可以通过使用 Redis:hMset 的方式来进行插入,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Redis;

class RedisController
{
public function set() {
$key = 'HSET';
$value= [
'id' => '1',
'name' => 'test',
'mess' => 'This is test'
];
Redis::hMset($key,$value);
}

}

Command & Job

Redis 通常是一个缓存服务,主要用于作为中间层进行,我们可以通过使用 Reids 配合 Laravel 作为队列,通过 Laravel 队列所支持的 Command 来将 Redis 信息提取后映射到 MySQL 或其他数据库中。

在本文中,我们主要理解 Laravel 队列以及 Job(工作线程) 和 Command 的使用,同样的我们也可以通过 Controller 来进行调用 Job。

我们可以使用 Laravel artisan 命令来创建一个工作线程,并命名为 RedisJobTest

1
php artisan make:job RedisJobTest

创建完后他会在 app/Jobs/ 目录下生成一个 RedisJobTest.php 的 PHP 类,我们需要在里面进行编辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php  

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Redis;

class RedisJobTest implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

private $key;

/**
* Create a new job instance. * * @return void
*/ public function __construct(string $key)
{
// key
$this->key = $key;
}

/**
* Execute the job. * * @return void
*/ public function handle()
{
$llen = Redis::connection()->LLEN($this->key);
$lineToint = (int)$llen;

return dump($lineToint);
}
}

之后我们还需要创建一个命令,用于调用该队列,同样的我们也使用 Artisan 命令来进行创建:

1
php artisan make:command RedisJobCommand

然后在 app/Console/Commands/RedisJobCommand.php 下,来调用我们的工作线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php  

namespace App\Console\Commands;

use App\Jobs\RedisJobTest;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class RedisJobCommand extends Command
{
/**
* The name and signature of the console command. * * @var string
*/ protected $signature = 'command:redis_job_test';

/**
* The console command description. * * @var string
*/ protected $description = 'Command description';

/**
* Create a new command instance. * * @return void
*/ public function __construct()
{
parent::__construct();
}

/**
* Execute the console command. * * @return mixed
*/ public function handle()
{
echo 'Redis run start';

RedisJobTest::dispatch('SET')
->delay(now()->addMinutes(1));

echo 'Redis run end';
}
}

在上述的 Code 中,我们主要通过 $signature 类型来定义一个命令,同样的我们也可以在 $description 添加该命令的方法和描述,最后在 handle 方法中写入 RedisJobTest::dispatch 来调用 RedisJobTest 工作线程。

1
通过上述的流程演示,我们可以通过工作线程来实现 Redis 锁,在 Laravel Job 中的 ```handle()``` 方法下,添加 Redis 锁即可:
1
2
3
4
5
6
7
Redis::throttle('key')->allow(10)->every(60)->then(function () {
// 任务逻辑...
}, function () {
// 无法获得锁...

return $this->release(10);
});

上述 code 中,主要 Redis 中的频率限制,也就是限制指定类型每 60 秒只执行10次,如果没有锁,那么一般情况下将会导致任务被放回队列使其被重试。

在大量的数据涌入的情况下可能会导致数据库的崩溃从而出现错误,因此我们需要使用到 Redis 锁,这些在 Laravel 中主要被称之为频率限制,我们可以翻阅官方文档来检索我们需要的 队列 | 综合话题 |《Laravel 6 中文文档 6.x》| Laravel China 社区 (learnku.com)

在官方文档中,我们也可以在调用队列的时候对其进行延迟分发,这主要通过 delay 方法来进行实现,详细的可以查阅官方文档的描述 队列 | 综合话题 |《Laravel 6 中文文档 6.x》| Laravel China 社区 (learnku.com)

Laravel Email 认证

Laravel 为开发者提供了一种非常简便的方法来实现出 Email 认证,很遗憾的是官方文档所提供的信息并不完整。

发送

MustVerifyEmail

首先,我们直接在 app/User.php 加上 MustVerifyEmail 接口使让其成为 User.php 的接口即可:

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable implements MustVerifyEmail
{
……
}

.env

当配置接口类之后,我们还需要配置 .env 文件,并在此修改其邮箱的服务器以用于发送邮件:

1
2
3
4
5
6
7
8
MAIL_DRIVER=null
MAIL_HOST=null
MAIL_PORT=null
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"

保护路由

Laravel 的 Auth\VerificationConteroller 类包含了发送验证链接和看验证 Email 的必要逻辑。这都将通过 verify 选项传递给 Auth::routes方法中,因此我们需要在 web.php 中增加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Auth::routes(['verify'=>true]);
Route::group([],function () {
Route::get('/home', 'HomeController@space')->name('home')->middleware('verified');
});

当我们在 get 路由后加入 middleware('verified') 方法后,将会自动验证当前用户使用邮箱是否经过验证,通过验证的用户将会在 users 数据库表中 email_verified_at字段中添加其验证时间。

验证重定向

如果要设置验证完成后主要通过 app/Http/Controllers/Auth/VerificationController.php 类中的 $redirectTo 属性来进行设置,默认的是跳转至用户的个人空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\VerifiesEmails;

class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/

use VerifiesEmails;

/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;

……
}

如果在登录后验证邮箱时出错,可通过下述两条 artisan 命令来清理下 Laravel 缓存:

1
2
php artisan config:cache
php artisan cache:clear

文本

邮箱验证

Notifications

在 Laravel 中,我们可以通过使用 php artisan make:notification VerifyEmail 来新建一个 VerifyEmail 邮件通知,正常情况下他默认存储在了 vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php 下。

此 时在 toMail 方法下,来自定义邮件中的用语:

1
2
3
4
5
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->action('View Invoice', $url)
->line('Thank you for using our application!');

sendEmailVerificationNotification

当你通过使用 artisan 命令创建一个邮件通知后,并不代表已经完成了,还需要在 app/User.php 中添加一个 sendEmailVerificationNotification 即“发送电子邮件验证通知”方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

namespace App;

use App\Notifications\VerifyEmail;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable implements MustVerifyEmail
{
……
public function sendEmailVerificationNotification()
{
$this->notify(new VerifyEmail);
}
}

notifications

既然当 Notifications 以及 sendEmailVerificationNotification 都配置完成了,我们还需要来自定义邮件的模板:

1
php artisan vendor:publish --tag=laravel-notifications

此时会将 /vendor/laravel/framework/src/Illuminate/Notifications/resources/views 内容复制到 /resources/views/vendor/notifications 下。

当然你如果需要将所有 Markdown 通知组件导出自己的项目中进行自定义:

1
php artisan vendor:publish --tag=laravel-mail

Laravel 会将/vendor/laravel/framework/src/Illuminate/Mail/resources/views目录内容复制到/resources/views/vendor/mail下。

需要注意的是,该目录会包含除组件之外的 resources/views/vendor/mail/html/themes目录,该目录下存储着默认的主题文件,您可以自行定义并分享。

重置密码

ResetPassword

在进行下一步之后,我们需要来对重置密码的文本模板进行更改,和 邮箱验证 相差无几,需要通过使用 artisan 命令:

1
php artisan make:notification ResetPassword

之后将从 vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php 文件复制到 app/Notifications/ResetPassword.php中,因此我们可以参考 vendor 内的文件结构写入app/Notifications目录下。

sendPasswordResetNotification

ResetPassword 准备完成之后,我们需要通过在app/User.php文件中添加一个sendPasswordResetNotification方法,来使得 ResetPassword 通知被正常使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App;

use App\Notifications\VerifyEmail;
use App\Notifications\ResetPassword;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable implements MustVerifyEmail
{
……
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPassword($token));
}
}

Laravel Eloquent 序列化

在构建 JSON API 的时候,我们需要通过使用 Eloquent 所提供的一些简便方法来进行实现。需要注意的是我们可以通过设置返回的 header来进行返回 具有人类可读 的输出。

在官方文档中我们可以看到,我们可以序列化为数组或者字符串形式,但实际上,并不是这样 直接返回 return $data 即可返回出 json。因此官方文档所提供的 toJson \ toArray都输出的是Json格式内容。

且返回的数据中文均不是人类具有可读性的 \x000 格式,即 Unicode16 格式,无论你在返回中添加 JSON_UNESCAPED_UNICODE 都无济于事。

序列化

1
2
3
4
5
6
7
public function index()
{
$issue = IssuesModel::all();
return response()->json($issue,200,['Content-Type'=>'application/json;charset=UTF-8',
'Charset'=>'utf-8'],
JSON_UNESCAPED_UNICODE);
}

因此他返回的是一个 具有人类可读 的 JSON 类型文本,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[
{
"id": 1,
"titles": "……",
"datetimes": "2021-05-17 03:27:00",
"names": "……",
"……": "……",
"……": "……",
"……": "……",
"……": "……",
"……": "2021-05-17 03:27:42",
"……": "2021-05-17 03:27:42",
"……": "……",
"……": null,
"……": null,
"……": "……",
"……": null,
"……": null,
"……": "……",
"……": "……",
"……": "……",
"……": "……",
"……": null
}
]

黑名单与白名单

黑名单

在官方的文档中,黑名单被称之为更具直观的 “ 隐藏输出 ”,即从字面意思上理解不输出当前属性的值,我们可以在需要输出的 Eloquent ORM 模型 中保护属性中添加一个 $hidden 属性即可。

1
2
3
4
5
6
7
8
9
10
11
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class TestModel extends Model
{
……
protected $hidden = ['titles','datetimes','names'];
}

因此相应的 json 对象也不会进行输出,如原先的 ['titles','datetimes','names'] 都不会在下述的返回响应中不会输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"id": 1,
"……": "……",
"……": "……",
"……": "……",
"……": "……",
"……": "2021-05-17 03:27:42",
"……": "2021-05-17 03:27:42",
"……": "……",
"……": null,
"……": null,
"……": "……",
"……": null,
"……": null,
"……": "……",
"……": "……",
"……": "……",
"……": "……",
"……": null
}
]

白名单

白名单在官方文档中也被称之为 “白名单”,因此在本文中我们可以使用一种更为直观的方法来以 “ 需要输出的对象 ” 来更加直观的理解。白名单的输出也非常简单,和上述步骤一样在 Eloquent ORM 模型中添加一个$visible

1
protected $visible = ['titles','datetimes','names'];

因此输出的也是只有相应的 json 对象:

1
2
3
4
5
6
7
8
[
{
"id": 1,
"titles": "……",
"datetimes": "2021-05-17 03:27:00",
"names": "……",
}
]

Laravel Flysystem

Laravel 通过 Frank de Jonge 内的 Flysystem 扩展包为开发者提供了一个强大的文件系统抽象概念。配置 Flysystem 的配置在config/filesystem.php中,再次我们可以配置所有的文件存储位置以及文件磁盘。

public

public 磁盘被称之为“公共磁盘”,因此他主要适用与公开的访问文件,默认情况下由本地(local)进行驱动,并存储在storage/app/publi目录下。如果需要让此在网络情况下也可以访问,需要创建public/storagestoraage/app/public的符号链接。

这种方式可以将公开文件都保存在一个目录下,以及在使用停机时间部署时可以轻松在不同的部署之间共享这些文件。

此时我们可以通过使用 下述 artisan 命令来创建符号链接:

1
2
$ php artisan storage:link
The [public/storage] directory has been linked.

权限

同样的在 public 中,可见行为目录的 755(拥有读、写、执行权限)和文件的644(拥有读写权限),我们也可修改filesystem配置文件中的权限映射:

1
2
3
4
5
6
7
8
9
10
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' =>[
'file'=>[
'public'=>0600,
'private'=>0700
]
]
],

在上述配置中,我们将 /public 赋予了0600即只有读写权限,而在 /private 目录下则赋予了 0700的可读、写、执行权限。

文件上传

local

在 Laravel 中,要实现文件的上传需要通过使用 file以及store的搭配,通过 file来告诉 Laravel:”你需要上传谁,及获取谁的表单”。而store则是告诉 Laravel 你需要存储在哪个目录下

1
2
//web.php
Route::post('/upload',"PostController@update");
1
2
3
4
5
6
7
{{--inbar.blade.php--}}
<form action="/upload" method="post" enctype="multipart/form-data">
@csrf
<input type="hidden" name="_token" value="<?php echo csrf_token()?>">
<input type="file" name="img">
<button type="submit">Up File</button>
</form>
1
2
3
4
5
6
7
8
9
10
11
12
//    Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
$path = $request->file('img')->store('avatars');
return $path;
}

在上述的 Controller code 中,我们通过了获取名为 img 表单所上传的文件后存储至avatarsstorage/app/avatars目录下。值得注意的是默认情况下 store方法会自动生成一个唯一ID 作为文件名称


当我们上传图像的时候,将会在 avatars目录下显示出我们刚刚上传的图像,并经过了store来自动生成一个唯一的ID作为文件名称。

Tencent cos


在上面我们介绍了 Laravel 文件的存储中,说到了文件磁盘,其中主要可以进行本地和远程的文件上传。在 Laravel 我们通常会使用国内较快的 腾讯云 COS,而 Laravel 默认的是 AWS s3,本文主要使用 Tencent cloud cosv5 作为演示,首先需要安装依赖:

安装与配置

1
composer require freyo/flysystem-qcloud-cos-v5

当一切完成之后想 config/app.php 文件内providers中添加以下信息:

1
2
3
4
5
6
7
8

'providers' => [

/*
* Laravel Framework Service Providers...
*/
……
Freyo\Flysystem\QcloudCOSv5\ServiceProvider::class,
env and filesystems

在然后将下述 code 粘贴并修改到 .end文件中:

需要参考腾讯云 COS 管理内和密钥页面进行填写

1
2
3
4
5
6
7
8
9
10
11
12
13
COSV5_APP_ID=
COSV5_SECRET_ID=
COSV5_SECRET_KEY=
COSV5_TOKEN=null
COSV5_TIMEOUT=60
COSV5_CONNECT_TIMEOUT=60
COSV5_BUCKET=
COSV5_REGION=
COSV5_CDN=
COSV5_SCHEME=https
COSV5_READ_FROM_CDN=false
COSV5_CDN_KEY=
COSV5_ENCRYPT=false

当修改完成后将下述 code 复制到 config/filesystems.php 文件内的disks下,无需修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'disks' => [
……
'cosv5' => [
'driver' => 'cosv5',
'region' => env('COSV5_REGION', 'ap-guangzhou'),
'credentials' => [
'appId' => env('COSV5_APP_ID'),
'secretId' => env('COSV5_SECRET_ID'),
'secretKey' => env('COSV5_SECRET_KEY'),
],
'timeout' => env('COSV5_TIMEOUT', 60),
'connect_timeout' => env('COSV5_CONNECT_TIMEOUT', 60),
'bucket' => env('COSV5_BUCKET'),
'cdn' => env('COSV5_CDN'),
'scheme' => env('COSV5_SCHEME', 'https'),
'read_from_cdn' => env('COSV5_READ_FROM_CDN', false),
],

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//    Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
/*
* 1.获取 名为 img 表单所提交的文件
* 2.选择 cosv5 作为文件磁盘
* 3.将 $file 存储至 "picture_class" 目录下
* 4.生成并返回该文件的 url。
*/

$file = $request->file('img');
$disk = Storage::disk('cosv5');
$file_content = $disk->put("picture_class",$file);
$file_url = $disk->url($file_content);
return ($file_url);
}
文件名称

在 local 一节中我们说道了 store方法会自动生成一个唯一的ID 作为文件的名称,因此在提交的时候唯一性是保证了,但是可读性会大大缩小。因此我们可以通过下述几个方法来对文件名称进行操作:

ID DA
getClientOriginalName 获取原来的文件名
getClientOriginalExtension 获取文件的扩展名
getClientMimeType 文件的类型
1
2
3
4
5
6
7
8
$file = $request->file('img');
$extension = $file->getClientOriginalName();
$filename = date('Y-m-d G_i_s') . ".".$extension;

$disk = Storage::disk('cosv5');
$file_content = $disk->putFileAs('picture_class',$file,$filename);
$file_url = $disk->url($file_content);
return $file_url;

除了上述的 getClient 方法外,我们还需要配合date方法来共同完成,因此我们通过使用 dataY-m-d G_i_s 来进行实现,分别表示 年份-月份-日期 小时_分周_秒数 等,最终输出 2021-05-12 23_46_00

Laravel 文件结构

在不同的开发环境和项目中,文件结构是一个非常重要的一点,如maven的文件结构可以分为src/main/等等,在这些结构中都会有一个默认的“潜规则”。如你在开发项目的时候,还在本地测试阶段,而你却将项目源代码放到了/src/main目录下,这则会让同事觉得你有点问题。Laravel的文件结构也一样,如下:

ID DA FA
app 用于包含应用程序的核心代码 开发项目的时候所有类都将存放于此
Console 包含应用程序中所有自定义的Artisan命令
Events* 默认情况并不存在,主要用于放置事件类,用于警告应用程序和其他部分发生了一个给定的操作
Exceptions 包含应用程序的异常处理,也可放置应用程序跑出的任何异常
Http 包含控制器、中间件、表单请求,处理应用程序请求的所有逻辑基本都将放置在此目录
Jobs* jobs目录是一般情况下并不存在的,用于包含应用程序的队列
Listeners* 默认情况下并不存在,主要用于包含事件处理类
Mail* Mail目录并不存在,主要用于包含应用程序发送邮件的类
Notifications* 默认情况下不存在,用于包含应用程序发送的所有事物同志
Policies* 默认情况下并不存在,主要用于包含授权策略类,即用户是否可以对一个资源进行访问等
Providers 用于包含应用程序的所有服务提供者,服务提供者将通过服务容器绑定服务引导程序。在新的Laravel应用中,此项目母吕将会包含一些应用提供者,可根据自己的需求将自己添加到此母吕中
Rules* 默认情况并不存在,主要包含应用程序自定义验证规则对象
bootstrap 主要包含app.php以及cache目录 cache用于存放框架所自动生成来提升整体性能文件
Config 即配置包含了配置文件 可阅读这些配置文件来掌握Laravel
database 即数据填充和模型工厂类 当然顾名思义你也可以用于放置数据库文件?
public public目录包含了首页文件index.php 还可用于放置资源文件如js/css/img
resources 包含了图像和一些未编译的文件 你可用于存放SASS这些
routes routes 目录包含了所有的路由定义类 此外还有默认存在的api.php channels.php console.php web.php路由文件。
web.php 放置在了web中间件组的路由,提供了会话状态、CSRF防护和cookie加密
api.php 放置在api中间件组的路由,提供频率限制,通过路由进入应用请求通过令牌进行认证
console.php 定义所有基于终端命令闭包汉书的文件,每个闭包汉书都被绑定到了一个命令示例且允许命令号IO方法的进行简单交互
storage 哟用于存储编译后的blade、session、缓存、框架生成的文件 内包含了app、framework、logs三个子目录,分别对应应用生成、框架生成、日志生成
storage/app/public 用于包含用户生成的文件
tests 即用于包含自动化测试文件 此处潜规则是每个自测试类都以test作为后缀
vendor 包含项目中所有的 composer 依赖包
📖 more posts 📖