16 06 2020

PHP框架 - Laravel 5.6

一、composer安装

1.1 composer介绍

composer是php用来管理依赖关系的工具,你可以在自己的项目中申明所依赖的外部关系库,composer会帮你安装这些依赖的库文件;一句话,composer是一个工具,是为php项目准备的软件管家。


1.2 composer工作原理

image.png


1.3 composer安装

windows安装:下载Composer-Setup.exe,安装目录选择php对应版本的php.exe所在位置

命令行安装:

php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"


注意:如果是安装composer.exe文件,一定要安装在使用的版本的php的安装目录,也就是php.exe所在目录


1.4 镜像地址设置

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/   或者  composer config -g repo.packagist composer https://packagist.phpcomposer.com


镜像原理:

image.png


1.5 配置文件修改

①开启php.ini扩展配置:

extension=php_openssl.dll    

extension=php_pdo_mysql.dll  (PDO)

extension=php_mbstring.dll  (mbstring)

extension=php_fileinfo.dll  (验证码)

extension=php_curl.dll       (请求发送)

②开启http.conf配置

LoadModule deflate_module modules/mod_deflate.so

LoadModule rewrite_module modules/mod_rewrite.so


1.6 使用composer更新composer 

composer self-update


1.7 使用composer安装项目依赖

composer install :(项目第一次执行composer,没有composer.json文件)


它将会去读取你的composer.lock而非composer.json,并且以此为标准去下载依赖。

当你本地没有composer.lock的时候,它所做的事情和composer update其实并没有区别。

这意味着,只要你本地有一份composer.lock,你就可以保证无论过去了多久,你都能拉到相同的依赖。而如果你把它纳入你的项目的版本控制中,那么你就可以确保你项目中的每一个人、每一台电脑,不管什么系统,都能拉取到一模一样的依赖,以减少潜在的依赖对部署的影响。当然,请记得,你应该使用的命令是composer install。


composer update:(有composer.json文件之后)

当你执行update的时候,composer会去读取composer.json中指定的依赖,去分析他们,并且去拉取符合条件最新版本的依赖。然后他会把所拉取到的依赖放入vendor目录下,并且把所有拉取的依赖的精确版本号写入composer.lock文件中。




二、Laravel框架安装

2.1 安装具体版本命令

composer create-project laravel/laravel=5.6.* my_laravel --prefer-dist

laravel/laravel=5.6.*   这个* 代表这里安装5.6的最高版本

image.png

image.png


2.2 查看框架版本信息:php  artisan --version


2.3 启动服务:php  artisan serve


2.4 laravel框架目录结构

① app目录:项目的核心目录,主要用于存放项目核心代码,也包括控制器、模型

 image.png

image.png

② bootstrap目录:laravel启动目录,引导框架并配置自动加载的文件,该目录还包含了一个 cache 目录,存放着框架生成的用来提升性能的文件,比如路由和服务缓存文件。

③ config目录:项目的配置目录,主要存放项目配置文件

image.png

④ database目录:数据填充和迁移文件

⑤ public目录:项目入口文件和系统静态资源目录(css、js、img)

⑥ resources目录:目录包含了语言包、视图和未编译的资源文件(如 LESS、SASS 或 JavaScript)

⑦ routes目录:目录包含了应用的所有路由定义,Laravel 默认包含了几个路由文件: web.php, api.php, console.php 和 channels.php。

⑧ storage目录:storage 目录包含编译的 Blade 模板、基于文件的会话和文件缓存、以及框架生成的其他文件。这个目录被细分成 app 、 framework 和 logs 三个子目录。 app 目录可以用来存储应用生成的任何文件。 framework 目录用来存储框架生成的文件和缓存。最后, logs 目录包含应用的日志文件。

总结:存放缓存文件和日志文件,在linux系统下,该目录需要有写权限

⑨ vendor目录:主要用于存放第三方类库文件,比如:邮件发送类文件、验证码类文件、laravel框架源码文件等等。

⑩ .env文件:设置系统相关环境信息文件(config目录里面的配置文件内容一般都是读取该文件里面的配置信息)

①① artisan脚手架文件

注意:使用artisan文件需要注意2点

a、 php必须添加环境变量,必须保证版本

b、 artisan必须存在命令行当前的工作路径下,也就是框架的根目录下

①② composer.json:依赖包配置文件

声明当前需要的软件依赖,不能删除,composer需要读取使用


2.5 laravel启动方式

①  方式1, 命令启动:php artisan serve  该启动方式不需要启动apache/nginx ,不推荐使用,能跑php,但是不启动数据库

②  方式2,  使用wamp环境,配置个虚拟主机

image.png


2.6 配置框架app key:php artisan key:generate


三、Laravel入门基础

3.1 laravel路由介绍

a、路由配置文件

image.png

b、路由定义

image.png

image.png

c、请求方式有哪些

image.png

image.png

d、路由参数

image.png

还可以通过?形式get传参:

image.png

image.png

路由别名:

image.png

获取路由列表命令(查看系统已有路由):php artisan route:list

image.png

e、路由群组

image.png

image.png


3.2 控制器使用

a、控制器文件写在哪里

image.png

b、控制器命名

大驼峰命名 + Controller.php

c、创建控制器

php artisan make:controller TestController                    默认路径Controllers目录下

php artisan make:controller Admin/AdminController     指定路径,Controllers/Admin目录下

image.png

image.png

image.png

d、控制器路由

image.png

image.png

e、接收用户输入

① 使用Illuminate\Support\Facades\Input类,Input静态接收请求参数

image.png

image.png

image.png

Facades:门面思想。门面是一个介于类的实例化与没有实例化中间的一个状态,其实是类的一个接口实现。这个状态下可以不实例化类,但是可以调用类中的方法。说白了就是静态方法。

在laravel中如果需要使用facades,但又不想写那么长的引入操作,则可以在config/app.php中定义长串的别名(aliases数组中定义别名)。

image.png

② 使用 Illuminate\Http\Request类,Request依赖注入的方式获取输入参数

image.png

image.png

③ 使用Illuminate\Support\Facades\Request类,Request静态接收请求参数

image.png

image.png


3.3 DB类操作数据库

a、引入DB类文件

image.png

注意:使用DB类,需要use  Illuminate\Support\Facades\DB类,DB门面类在app.php文件中已经定义了别名DB,可以直接use DB,不需要写太长的空间

image.png

b、新增数据

image.png

image.png

c、修改数据

image.png

image.png

d、查寻数据

image.png

//获取数据
public function getData(){
   
//1.获取所有数据
   
$db = DB::table('user');
   
$data1 = $db->get();
   
//var_dump($data1);
   
foreach ($data1 as $k=>$v){
       
//get查寻出来都是对象,不能再用访问数组的方式访问,必须访问对象方式访问数据
       
var_dump($v->name);
   
}
   
//2.大于...
   
$data2 = DB::table('user')->where('id','>',2)->get();
   
dump($data2);
   
//3.获取单行或列
   
$one = DB::table('user')->first(); //返回一个对象,相当于limit(1)
   //$one = $db->where('name','
菲兹')->first();
   
dump($one);
   
//4.获取某个具体的值
   
$data3 = DB::table('user')->where('id','=',3)->value('email');
   
dump($data3);
   
//5.获取某些字段的值
   
$data4 = DB::table('user')->select('name','age','email')->get();
   
dump($data4);
   
//6.分块查寻
   
echo '<hr/>';
   
DB::table('user')->orderBy('id')->chunk(1,function($user){
       
foreach ($user as $k=>$v){
           dump(
$v);
       
}
   })
;
}

e、排序操作

public function paixu(){
   
$db = DB::table('user');
   
$data1 = $db->orderBy('id','desc')->get();
   
dump($data1);
}

f、分页操作

public function fenye(){
   
$db = DB::table('user');
   
//limit:限制输出的条数
   
//offset:从什么地方开始
   
//组合起来等价于  limit 2,1
   
$data1 = $db->limit(2)->offset(1)->get();
   
dump($data1);
}

g、删除操作

image.png

public function delete(){
   
$db = DB::table('user');
   
$data1 = $db->where('id','<',3)->delete();
   
dd($data1); //返回删除数据的条数
}

h、执行任意的sql语句

image.png

public function doSql(){
   
//1.statement语句
   
$data1 = DB::statement("insert into user values(6,'卡莎',18,'kasha@163.com')");
   
var_dump($data1);
   
//2.select语句
   
$data2 = DB::select("select * from user");
   
dump($data2);
}



3.4 视图操作

a、视图写在哪里

视图可以进行分目录管理的

image.png

b、视图文件的命名与渲染

image.png

image.png

image.png

c、变量的分配与展示

image.png

public function assignVar(){
   
$date = date('Y-m-d H:i:s',time());
   
$day = '星期六';
   
//return view('article.list',['date'=>$date,'day'=>$day]);
   
return view('article.list')->with(['date'=>$date,'day'=>$day]);
}

d、compact()函数使用

compact函数使php内置函数,跟框架没有关系,主要作用用于打包数组,在当前的符号表中查找该变量名并将它添加到输出的数组中,变量名成为键名而变量的内容成为该键的值!!!

语法:compact('变量名1','变量名2',...)

image.png

e、在模板视图中使用函数

image.png

语法:{{函数名(参数1,参数2)}}

说明:函数可以是php内置的函数,也可以是laravel框架中定义的

image.png

f、循环与分支

image.png

image.png

image.png

g、模板继承

image.png

父级页面:

image.png

子级页面:

image.png

h、文件包含

语法:@include('模板文件名')    文件名不带后缀

image.png

i、外部文件引入

在laravel框架中,封装了一个asset()方法

image.png

注意:href = "{{asset('css/blog/')}}"  asset()方法的参数可以是单级目录,也可以是多级目录


3.5 CSRF攻击

a、什么是csrf攻击

image.png

b、csrf使用

image.png

image.png

image.png

image.png

注意:有一种情况是没得选择的,只能使用csrf_token,就是使用ajax异步提交表单方式

区别:csrf_token只是输出了token值,csrf_field输出了整个input隐藏域

c、csrf验证中排除列外路由

image.png

image.png

action地址写法一:

image.png

image.png

action地址写法二:

image.png

image.png



3.6 模型操作(AR模式)

a、模型介绍

image.png

b、模型文件位置和模型文件创建

image.png

使用命令创建模型:php artisan make:model Admin\Article

image.png

image.png

c、定义模型

image.png

//定义模型关联的数据表
protected $table = 'user';
//定义主键
protected $primaryKey = 'id';
//定义禁止操作时间
public $timestamps = false;  //数据表中没有created_at updated_at字段时必须禁用!!!
//设置允许写入的字段,使用create()方法的时候必须定义$fillable属性
protected $fillable = ['name','age','email'];
//设置不允许写入字段, $fillable $guarded 只能二选一设置
//protected $guarded = ['price'];


d、在控制器中使用模型

use App\Admin\User;                     //在控制器中操作模型,use模型

方式①:AR模式

实例化模型,然后再去使用类,例如:  $model = new User();   $model->get();

image.png

public function userAdd1(){
   //1.实例化模型
   $userModel = new User;      //dd($userModel);
   //2.给属性赋值,字段与类的属性映射
   $userModel->name = Input::get('name');
   $userModel->age = Input::get('age');
   $userModel->email = Input::get('email');
   $res = $userModel->save();
   dd($res); //这种方式返回 bool 类型结果
}

注意:上面这种方法可以完成数据的插入,但是开发中不建议使用

方式②:

直接像使用DB门面一样的的操作,以调用静态方法为主的形式,该形势下模型不需要实例化,例如: User::get();  等价于  DB::table('user')->get();  

image.png

public function addForm(){
   //1.加载静态页面视图
   return view('admin.user.useradd2');
}
public function userAdd2(Request $request){
   //2.使用User::create()方式写入数据,依赖注入的方式接收变量
   $res = User::create($request->all());
   //$data = Input::all();
   //var_dump($data);
   dd($res);  //这种方式返回 obj 类型结果
}


注意:如果使用create()方法,则需要在模型中定义fillable属性 允许写入的字段,如果数据表中没有时间相关字段也需要禁用时间自动更新功能

e、查询操作

public function userList(){
   //1.查寻单条指定id的数据
   $res = User::find(9); //返回 obj
   dump($res);
   dump('姓名:'.$res->name.' 年龄:'.$res->age);
   //2.查寻所有数据转成数组
   $res3 = User::get()->toArray();
   dump($res3);
   //3.查寻符合条件的第一条数据
   $res4 = User::where('id','>',6)->first()->toArray();
   var_dump($res4);
   //4.all()方法
   $res5 = User::all(); //all()方法查询,不支持链接其他辅助查寻方法
   dump($res5);
   //5.get()方法获取某些字段
   $res5 = User::where('id','>',12)->get(['id','name'])->toArray();
   var_dump($res5);
   echo '<br>';
   //6.select()获取某些字段
   $res6 = User::where('id','>',10)->select('id','name','age')->get()->toArray();
   dump($res6);
}

f、修改数据

image.png

public function userEdit(){
   //1.AR模式修改操作
   $data = User::find(6);
   dump($data); //obj
   //给要修改的字段赋值
   $data->email = 'aike@163.com';
   //保存修改
   $res1 = $data->save();
   dump($res1);

   //2.模型使用update方式更新数据
   $res2 = User::where('id',6)->update(['email'=>'aike2@163.com']);
   dump($res2);   //int 1|0
}

g、删除数据

image.png

public function userDelete(){
   //1.模型删除操作
   $data = User::find(10);
   $res1 = $data->delete();
   var_dump($res1);   //返回bool true|false

   //2.DB类里面的方式删除
   $res2 = User::where('id','>',14)->delete();
   var_dump($res2); //int 返回受影响的行数
}



3.7 自动验证

a、自动验证介绍

image.png

b、演示浏览器禁用js功能

未禁用之前:

image.png

设置浏览器禁用js:

image.png

禁用以后:

image.png

image.png

注意:所以一个功能完善的应用,前后端都要做验证,不止单独的前端或者单独的后端单方面做验证!!!

c、获取/判断请求方式

public function userAdd3(Request $request){
   //1.请求方式判断一
   $method1 = $request->isMethod('POST');  //true
   var_dump($method1);
   //2.请求方式判断二
   $method2 = request()->method();     //POST
   var_dump($method2);
   //3.请求方式判断三
   $method3 = Input::method();         //POST
   var_dump($method3);
   //4.请求方式判断四
   $method4 = Request::METHOD_POST;    //POST
   var_dump($method4);
   $method5 = FacRequest::method();    //POST 静态Request的别名 FacRequest
   var_dump($method5);
}


d、快速验证($this->validate验证)

image.png

注意:多个验证规则使用 "|" 字符进行隔开

语法:$this->validate(数据对象,数组形式的验证规则)


image.png

//1. 快速验证($this->>validate验证)
public function addForm3(){
   //1.加载静态页面视图
   return view('admin.user.useradd3');
}
public function uValidate(Request $request){
   //使用场景,返回到模板中
   if(Request::METHOD_POST == 'POST'){
       $input = $this->validate($request,[
           //验证规则
           'name'  =>  'required|between:2,10|alpha_dash',
           'age'   =>  'required|integer|between:18,100',
           'email' =>  'required|email|unique:user,email',
           'tel'   =>  'required',
       ],[
           'name.required' =>  '姓名必须填写',
           'name.between' =>  '姓名2-10个字符',
           'name.alpha_dash' =>  '姓名只能是字母、数字、破折号( - )以及下划线( _ ',
           'age.required' =>  '年龄必须填写',
           'age.integer' =>  '年龄请填写整数',
           'age.between' =>  '年龄18-100岁之间',
           'email.required' =>  '邮箱必须填写',
           'email.email' =>  '邮箱格式不对',
           'email.unique' =>  '邮箱已经存在',
           'tel.required'  =>  '手机号必须填写',
       ],[
           'name'  =>  '姓名',
           'age'   =>  '年龄',
           'email' =>  '邮箱',
           'tel'   =>  '手机号',
       ]);
       return ['msg'=>$input];
   }else{
       return ['code'=>100501,'msg'=>'请求方式错误'];
   }
}


image.png

<body>
<form action="{{route('ad3')}}" method="post">
   姓名:<input type="text" name="name" id=""><br/>
   年龄:<input type="text" name="age" id=""><br/>
   邮箱:<input type="text" name="email" id=""><br/>
   <input type="hidden" name="_token" value="{{csrf_token()}}">
   <input type="submit" value="提交">
</form>
@if ($errors->any())
   <div class="alert alert-danger">
       <ul>
           @foreach ($errors->all() as $error)
               <li>{{ $error }}</li>
           @endforeach
       </ul>
   </div>
@endif
</body>

响应效果:

image.png


e、独立验证

use Validator;
//2.独立验证
public function addForm5(){
   //1.加载静态页面视图
   return view('admin.user.useradd5');
}
public function duliValidate(Request $request){
   //使用场景,响应ajax
   if($request->isMethod('POST')){
       $validator = Validator::make($request->all(),[
           'name'  =>  'required|between:2,10|alpha_dash',
           'age'   =>  'required|integer|between:18,100',
           'email' =>  'required|email|unique:user,email',
           'tel'   =>  'required',
       ],[
           'name.required' =>  '姓名必须填写',
           'name.between' =>  '姓名2-10个字符',
           'name.alpha_dash' =>  '姓名只能是字母、数字、破折号( - )以及下划线( _ ',
           'age.required' =>  '年龄必须填写',
           'age.integer' =>  '年龄请填写整数',
           'age.between' =>  '年龄18-100岁之间',
           'email.required' =>  '邮箱必须填写',
           'email.email' =>  '邮箱格式不对',
           'email.unique' =>  '邮箱已经存在',
           'tel.required'  =>  '手机号必须填写',
       ],[
           'name'  =>  '姓名',
           'age'   =>  '年龄',
           'email' =>  '邮箱',
           'tel'   =>  '手机号',
       ]);
       //dump($validator);
       //dump(get_class_methods($validator)); //获取类里面的所有方法
       //如果有错误,返回true
       if($validator->fails()){
           return redirect()->back()->withErrors($validator);
       }
   }else{
       return ['code'=>100501,'msg'=>'请求方式错误'];
   }
}


f、表单验证(验证器验证)

创建表单验证类文件: php artisan make:request Admin/ArticleRequest

image.png


namespace App\Http\Requests\Admin;
//单个验证规则失败后停止验证所有规则
protected $stopOnFirstFailure = true;
/**
* 如果您打算在应用程序的其它部分处理请求的授权逻辑,只需从 authorize 方法返回 true
* @return bool
*/
public function authorize()
{
   return true;  //设置为true
}

/**
* 书写验证规则
* @return array
*/
public function rules()
{
   return [
       'name'  =>  'required|between:2,10|alpha_dash',
       'age'   =>  'required|integer|min:18|max:100',
       'email' =>  'email|unique:user,email',
       'tel'   =>  [
           'required',
           'unique:user,tel',
           'regex:/^1[3456789][\d]{9}$/'
       ],
       'pwd'   =>  'required|alpha_dash|between:6,16|confirmed', //confirmed属性写在原始密码字段上
       //'pwd_confirmation'  =>  'required|alpha_dash|same:pwd', //same,验证字段必须与给定字段匹配
       'pwd_confirmation'  =>  'required|alpha_dash',  //same 和 原始密码字段的confirmed有一个就行
       'pic'   =>  'nullable|image|max:100',   //laravel5.6bug,需要去修改允许上传的文件格式!!!
       //'pic'   =>  'mimes:jpg,jpeg,png,gif,bmp,webp|max:100',
   ];
}

//自定义错误信息
public function messages()
{
   return [
       'name.required' =>  '姓名必须填写',
       'name.between' =>  '姓名2-10个字符',
       'name.alpha_dash' =>  '姓名只能是字母、数字、破折号( - )以及下划线( _ )组成',
       'age.required' =>  '年龄必须填写',
       'age.integer' =>  '年龄请填写整数',
       'age.min' =>  '必须年满18',
       'age.max' =>  '年龄不超过100',
       //'email.required' =>  '邮箱必须填写',
       'email.email' =>  '邮箱格式不对',
       'email.unique' =>  '邮箱已经存在',
       'tel.required'  =>  '电话号码必须填写',
       'tel.unique'  =>  '电话号码已经存在',
       'tel.regex'  =>  '电话号码不正确',
       'pwd.required' => '密码不能为空',
       'pwd.between' => '密码6-16位字符',
       'pwd.alpha_dash' => '密码只能是字母、数字、破折号( - )以及下划线( _ )组成',
       'pwd_confirmation.required' => '确认密码不能为空',
       'pwd_confirmation.alpha_dash' => '确认密码只能是字母、数字、破折号( - )以及下划线( _ )组成',
       'pwd.confirmed' => '两次密码不一致',
       //'pic.mimes' =>  '请上传jpeg,bmp,png,gif,jpg格式图片',
       'pic.image' =>  '请上传jpg,jpeg,bmp,png,gif,webp格式图片',
       'pic.max'   =>  '上传图片大小不超过100kb',
   ];
}


use App\Http\Requests\Admin\User as UserValidate; //自定义表单验证
public function addForm4(){
   //1.加载静态页面视图
   return view('admin.user.useradd4');
}
//进行表单验证
public function zdyValidate(UserValidate $request){
   //获取通过验证的数据
   $valited = $request->validated();
   //dump($valited); //array
   //获取部分通过验证的数据
   //$valited2 = $request->safe()->only(['name','email']);
   //dd($valited2);
   //调用写入数据库方法
   $res = self::userAdd4($request);
   if($res){
       $data = ['code'=>100016,'msg'=>'添加成功'];
       //设置setEncodingOptions(JSON_UNESCAPED_UNICODE),返回数据禁止Unicode编码
       //return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
       return response()->json($data);
   }else{
       $data = ['code'=>100015,'msg'=>'添加失败'];
       return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
   }
}

public function userAdd4(Request $request){
   $salt = getRandomString($length = 15);  //获取盐str
   //密码加密
   //$pass1 = Crypt::encrypt($request->input('pwd'));              //一长串,188个字符
   $pass = Hash::make($request->input('pwd').$salt);    //60个字符
   $data = $request->except(['pwd','pwd_confirmation']);
   $data['pwd'] = $pass;
   $data['salt'] = $salt;
   return UserModel::create($data);
}


g、输出效果展示成中文:

image.png

① 语言包下载网址:https://packagist.org/,搜索laravel-lang,选择下载量最多、收藏最多的下载

image.png

② 下载包:

image.png

③ 查看文档:

image.png

image.png

④ laravel5-语言包安装命令:

在项目根目录下面执行语言包安装命令   composer require laravel-lang/lang:^3.0      或者   composer require laravel-lang/lang:^3.0 laravel-lang/publisher:^3.0

下载原始包文件位置:

image.png

⑤ 复制zh-CN文件夹到框架如下目录:

image.png

⑥ 修改laravel框架配置文件:config/app.php,修改 'locale'  => 'en'   为  'locale'  => 'zh-CN' 

image.png

⑦ 测试效果

image.png

⑧ 修改语言包中错误,resources/lang/validation.php 中age字段,  'age' =>'年轻'  改为   'age' => '年龄'

image.png

⑨ 语言包中添加字段 ,resources/lang/validation.php 中添加tel字段测试

image.png

image.png


h、修改laravel框架返回数据,禁止Unicode编码

① return json数据的地方加上setEncodingOptions(JSON_UNESCAPED_UNICODE)

return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);

② 修改文件: vendor\laravel\framework\src\Illuminate\Http\JsonResponse.php的构造函数,$this->encodingOptions = $options ;  修改为  $this->encodingOptions = JSON_UNESCAPED_UNICODE ;

public function __construct($data = null, $status = 200, $headers = [], $options = 0)
{
   //$this->encodingOptions = $options;
   $this->encodingOptions = JSON_UNESCAPED_UNICODE;

   parent::__construct($data, $status, $headers);
}


i、laravel框架中添加公共函数

① 在app目录下面新建Helper\functions.php文件

image.png

② 配置composer

打开根目录下的composer,在autoload项下面按照图示配置

image.png

 执行composer命令

 composer dump-auto

image.png



3.8 文件上传

a、表单方式上传

不考虑异步(js、ajax)上传,使用纯表单提交上传,需要注意点有以下:

① 表单type="file"   ,提交方式 method 为post  

② form表单具有enctype="multipart/form-data" 属性

multipart/form-data是指表单数据有多部分构成,既有文本数据,又有文件等二进制数据的意思 ;默认情况下,enctype的值是application/x-www-form-urlencoded,不能用于文件上传,只有使用了multipart/form-data,才能完整的传递文件数据。 

③ 具备一个提交按钮,submit可以直接提交,  button需要写js提交

注意:文件上传的核心 就是文件移动,move_upload_file()


b、超全局变量$_FILES 

image.png

c、处理上传文件

image.png

//3.8 文件上传
//加载静态页面
public function fileView(){
   return view('admin.user.files');
}
//处理文件上传
public function fileUpload(Request $request){
   if($request->isMethod('POST')){
       $file = $request->file('pic');
       //$pic = $request->pic;  两个获取结果一样,都是Illuminate\Http\UploadedFile对象

       //判断是否有上传文件 且 上传的文件是否有效
       if($request->hasFile('pic') && $request->file('pic')->isValid()){
           //获取文件的原始名称
           dump($request->file('pic')->getClientOriginalName());
           //获取文件扩展名
           dump($request->file('pic')->getExtension());
           //获取文件上传错误码,上传成功为0
           dump($request->file('pic')->getError());
           //获取文件原始后缀名
           dump($request->file('pic')->getClientOriginalExtension());
           //获取文件mime类型
           dump($request->file('pic')->getClientMimeType());
           //获取文件上传的错误信息
           dump($request->file('pic')->getErrorMessage());


           //移动文件
           $path = './uploads/avatar/'.date('Ymd',time());
           $fileName = md5(time().rand(100000,999999)).'.'.$request->file('pic')->getClientOriginalExtension();
           //返回 Symfony\Component\HttpFoundation\File\File 对象
           $request->file('pic')->move($path,$fileName);
           $data = $request->all();
           $data['pic'] = date('Ymd',time()).'/'.$fileName;
           //添加到数据库
           UserModel::create($data);
       }else{
           $data = ['code'=>100012,'msg'=>'上传失败'];
           return response()->json($data);
       }
   }else{
       $data = ['code'=>100010,'msg'=>'请求方式错误'];
       return response()->json($data);
   }
}


d、laravel5.6框架图片验证bug修改

① 原因:上传jpeg、jpg后缀图片,提示请上传图片文件; png、gif后缀的图片文件能够验证通过

② 添加允许上传的文件后缀

a、找到文件位置:D:\xxx\la56\vendor\laravel\framework\src\Illuminate\Validation\Concerns

b、找到文件名:ValidatesAttributes.php

c、找到validateImage()方法,添加允许上传的文件格式

public function validateImage($attribute, $value)
{
   return $this->validateMimes($attribute, $value, ['jpg','jpeg', 'png', 'gif', 'bmp', 'svg','webp']);
}

注意:多文件上传验证规则

image.png

image.png


e、封装一个文件上传函数

use Illuminate\Http\Request;
/**
* 多文件上传
* @param Request $request      *请求对象
* @param $fieldName            *表单字段名称
* @param $category             *保存文件的分类文件夹名称
* @return array|\Illuminate\Http\JsonResponse
*/
function multiFileUpload($request,$fieldName = null,$category = null){
   //$request->file($fieldName) array[obj] ,多图片上传的时候数据结构:数组里面是文件对象
   if($request->hasFile($fieldName) && $request->file($fieldName)){
       $result = [];
       foreach($request->file($fieldName) as $file){
           //移动文件
           $path = './uploads/'.$category.'/'.date('Ymd',time());
           $fileName = md5(time().rand(100000,999999)).'.'.$file->getClientOriginalExtension();
           $file->move($path,$fileName);
           $result[] = date('Ymd',time()).'/'.$fileName; //20190128/8df7306be.jpg
       }
       return $result;
   }
}


3.9 数据分页

a、laravel分页简介

在laravel里面完成分页是很简单的,它的思想和其他框架有些不一样,其他一些框架使用的分页类完成的,laravel是直接调用模型的分页方法,返回对应的数据和分页字符串


b、分页类文件位置

image.png


c、模型用法

image.png

语法:{{$保存数据的对象->links()}} 


public function paginate(){
   //1. 没有分页的效果
   $data1 = UserModel::select('id','name','age','email','tel','pic')->orderBy('id','desc')->get();
   //2.简单分页效果
   $data2 = UserModel::select('id','name','age','email','tel','pic')->orderBy('id','desc')->simplePaginate(10);
   //3.分页效果
   $data3 = UserModel::select('id','name','age','email','tel','pic')->orderBy('id','desc')->paginate(15);
   foreach($data3 as $k=>$v){
       $data3[$k]['pic'] = '/uploads/avatar/'.$v['pic'];
   }
   return view('admin.user.paginate',compact('data3'));
}

image.png

① 简单分页效果

image.png

② 普通分页效果

image.png


d、自定义分页视图效果

自定义分页视图的制作最简单的方法是使用 vendor:publish 命令将它们导出到 resources/views/vendor 目录:

使用命令php artisan vendor:publish --tag=laravel-pagination  移动文件

编辑default.blade.php 和 bootstrap-4.blade.php 文件修改显示效果

image.png


3.10 验证码

a、安装验证码依赖包

网址:https://packagist.org/

包名:搜索  captcha 

image.png

指定版本安装:composer require mews/captcha=3.0.2     这里安装mews/captcha  3.0.2版本

image.png


b、修改配置文件

config/app.php文件配置

① 注册提供商

//验证码服务提供者
Mews\Captcha\CaptchaServiceProvider::class,

② 配置aliases 键

'Captcha' => Mews\Captcha\Facades\Captcha::class,


c、自定义参数配置

使用命令生成配置文件:php artisan vendor:publish

image.png

image.png


'default' => [
   'length' => 5,
   'width' => 120,
   'height' => 36,
   'quality' => 90,
   'math' => true,
   //'expire' => 60,
],


d、实现验证码显示

返回URL:captcha_src()      返回图片:captcha()       返回HTML:captcha_img()

<img src="{{captcha_src()}}" alt="验证码" onclick="this.src=this.src+'?'+Math.random()">


e、验证码验证

'code'   =>  'required|captcha',
'code.required'  =>  '验证码不能为空',
'code.captcha'  =>  '验证码不正确',

image.png

image.png


3.11 数据表的迁移与填充


1、数据的迁移操作

a、介绍

迁移:创建数据表的操作 + 删除数据表的操作

填充:往数据表里面填充写入数据(数据的插入操作)


b、数据的迁移操作

在迁移过程中,操作可以分为两个部分:创建与编写迁移文件    执行迁移文件

迁移文件默认位置:

image.png

① 创建迁移文件

案例:创建一张表,假设数据表的名字叫做paper,迁移文件名:create_paper_table

创建的时候可以通过artisan命令来执行迁移文件的生成:php artisan make:migration 迁移文件名

/**
* Run the migrations.
*创建数据表
* @return void
*/
public function up()
{
   Schema::create('paper', function (Blueprint $table) {
       $table->increments('id');
       $table->timestamps();
   });
}

/**
* Reverse the migrations.
*删除数据表
* @return void
*/
public function down()
{
   Schema::dropIfExists('paper');
}


② 编写迁移文件代码

编写迁移代码,实现数据表的up方法和down方法,参考框架database\migrations\目录下原始的文件书写

案例要求:

image.png

$table表示整个表的实例,语法:$table->列类型方法('字段名',[长度/值范围])->列修饰方法();


public function up()
{
   Schema::create('paper', function (Blueprint $table) {
       $table->increments('id');
       $table->string('paper_name',100)->notNull()->unique();
       $table->tinyInteger('total_score',tinyint)->default(100);
       $table->integer('start_time')->nullable();
       $table->integer('duration');
       $table->tinyInteger('status')->default(1);
       $table->timestamps();
   });
}
public function down()
{
   Schema::dropIfExists('paper');
}


c、执行迁移文件

① 执行up方法(创建数据表)

image.png

第一次执行迁移文件,需要执行的命令:php artisan migrate:install   生成一张migrations表,如下:

image.png

执行命令:php artisan migrate     【执行迁移文件的,创建数据表】

image.png


② 执行down方法(删除数据表)

执行命令:php artisan migrate:rollback     【回滚最后一次的迁移操作,不会删除迁移文件】

image.png

image.png


注意:迁移文件的文件名不要做任何修改,要报错!!!

image.png



2、数据表填充器

填充操作就是往数据表中写测试数据的操作

a、填充器所在目录

image.png


b、创建填充器

使用命令:php artisan make:seeder      【建议写法:大写表名+TableSeeder】  如:PaperTableSeeder


class PaperTableSeeder extends Seeder
{
   public function run()
   {
       //
   }
}



c、编写填充器代码

注意:在填充器文件中可以使用DB门面去新增数据,但是需要注意,DB门面在使用的时候不需要用户再去引入,一旦引入则报错,可以直接使用

public function run()
{
   DB::table('paper')->insert([
       'paper_name'    => '07年中考',
       'total_score'   => 558,
       'start_time'    => strtotime('+7 days'),
       'duration'      => 120,
       'status'        => 1
   ], [
           'paper_name'    => '13年高考',
           'total_score'   => 556,
           'start_time'    => strtotime('+7 days'),
           'duration'      => 120,
           'status'        => 1
       ]
   );
}


d、执行填充器文件

使用命令:php artisan db:seed --class = 需要执行的种子文件名

php artisan db:seed --class=PaperTableSeeder

image.png

image.png



3.12 响应处理

在laravel框架中响应正常的情况有两种, 一是常规的直接响应,另外一个是ajax响应;其中展示视图和直接响应字符串都属于常规响应


1、 常规响应

return view('admin.user.lis');

return 'hello';


2、 ajax响应

① 常见的ajax响应数据类型

json、xml、text/html

image.png

案例:

image.png

a、发送请求

image.png


b、响应处理


//处理响应处理
public function ajaxResponse(Request $request){
   if($request->isMethod('GET')){
       $data = UserModel::get();
       return response()->json($data); //响应给laravel框架的必须是字符串or对象
       //return ['a'=>10,'b'=>100];  //转成obj
   }else{
       $data = ['code'=>100010,'msg'=>'请求方式错误'];
       return response()->json($data);
   }
}


② 跳转响应(重定向)

语法:

return redirect('路由');

return redirect()->to('路由');



3.13 会话控制(记忆)

session默认存到文件中,session文件的目录:storage/framework/sessions

① 使用session

控制器中引用 use Illuminate\Support\Facades\Session,  由于session门面在app.php中已经定义好了别名,所以在控制器中可以直接use  Session;

image.png

public function huihua(){
   //1. 存储一个变量
   Session::put('name','红家伙');
   Session::put('age','19');
   session_start();
   dump($_SESSION);  //这里原生获取不到
   //2. 获取一个变量
   echo Session::get('name').'<br>';
   //3.获取一个默认值
   echo Session::get('name2','那个.').'<br>';
   echo Session::get('name6',function(){
       return '就是她';
       }).'<br>';
   //4.获取所有session信息
   dump(Session::all());
   //5.检查某个session是否存在
   dump(Session::has('name'));
   //6. 删除一个session变量
   dump(Session::forget('name'));
   //删除session中全部变量
   Session::flush();
   dump(Session::all());
}



3.14 缓存操作

laravel为不同的缓存提供了统一的API,缓存配置位于config/cache.php。在该文件中指定使用哪个缓存,系统默认使用文件缓存,其缓存位置位于:storage/framework/cache/data

① 设置缓存

image.png


② 获取缓存

image.png


③ 删除缓存数据

image.png

④ 缓存数值的增加/减少

image.png

⑤ 获取并存储

image.png

image.png

public function huancun(){
   //1.设置一个缓存,如果存在,则覆盖
   Cache::put('name','那个人',100);
   //2.设置一个缓存,存在同名则不添加
   Cache::add('age','20',50);
   Cache::add('mimi','200',1000000);
   //3.永久存储
   Cache::forever('sex','');
   //4.获取值
   $value1 = Cache::get('name');
   dump($value1);
   //4.获取值,不存在则使用默认值
   $value2 = Cache::get('sign',function(){
       return '这个家伙很懒,什么都没留下';
   });
   dump($value2);
   //5.检查缓存中是否存在某个值
   if(Cache::has('sex')){
       echo '存在值';
   }else{
       echo '不存在值';
   }
   //6.从缓存中获取缓存,然后删除
   $value3 = Cache::pull('sex');
   dump($value3);
   dump(Cache::get('sex'));
   //7.从缓存中移出缓存数据
   $value4 = Cache::forget('age');
   dump($value4); dump(Cache::get('age'));
   //8.清除所有缓存,并且删除目录
   //Cache::flush();
   //9.缓存值增加/减少
   Cache::increment('mimi',10);
   Cache::decrement('mimi');
   //10.设置一个默认时间
   $time = Cache::remember('time',100,function(){
       return date('Y-m-d H:i:s',time());
   });
   dump($time);
   //11.永久存储
   $day = Cache::rememberForever('timeforever',function(){
       return date('Y-m-d',time());
   });
   dump($day);
}



3.15 中间件

中间件作为请求和响应的中间人,它是一种过滤机制类型。在laravel中通过中间件来进行后台用户是否登录的验证操作,防止后台用户翻墙操作。

image.png

a、创建中间件

php artisan make:middleware  中间件名


b、中间件所在目录

image.png

image.png


c、注册中间件

在laravel中,中间件有两种类型; 即全局中间件(不管是在前台还是在后台都执行)和路由中间件。全局中间件将在应用程序的每个HTTP请求运行,而路由中间件将被分配到一个特定的路由,中间件可在  模app\Http\Kernel.php 注册

该文件包含两个属性,$middleware 和 $routeMiddleware, $middleware属性用于注册全局中间件, $routeMiddleware用于注册路由指定中间件。

① 全局中间件

image.png

image.png

image.png


② 路由中间件 (直接路由中间件、路由分组中间件)

image.png

路由web.php中注册路由中间件

image.png

image.png


③ 特殊的一种,控制器中间件

image.png



3.16 联表查询

① 普通联表查询

数据来源:文章表、作者表

表1:文章表      t1    主表(跟在from关键词后面的表)

表2:作者表      t2    从表(跟在join关键词后面的表)

关联条件:文章表的author_id = 作者表的id

联表方式:左外连接

原始sql:select t1.id,t1.article_name,t2.author_name from article as t1 left join author as t2 on t1.author_id=t2.id;


public function lianbiao(){
   $data = DB::table('article as t1')
       ->select('t1.id','t1.article_name','t2.author_name')
       ->leftJoin('author as t2','t1.author_id','=','t2.id')
       ->get();
   dump($data);
}



3.17 模型关联

① 一对一关联关系

例如:一篇文章只有一个作者

a、创建模型

image.png

b、定义模型代码


class Article extends Model
{
   //定义模型关联的数据表
   protected $table = 'article';
   //定义主键
   protected $primaryKey = 'id';
   //定义禁止操作时间
   public $timestamps = false;
}


class Author extends Model
{
   //定义模型关联的数据表
   protected $table = 'author';
   //定义主键
   protected $primaryKey = 'id';
   //定义禁止操作时间
   public $timestamps = false;
}


c、关联模型的关联方法

注意:在写关联模型的时候要分析出谁关联谁,谁做主动关联的模型。 当前案例:文章关联作者,文章是主模型,需要关联代码写在主模型中

//模型关联操作:关联作者模型(一对一)
//语法
public function 被关联的模型名小写(){
   return $this->hasOne('需要关联模型的命名空间','被关联模型的关系字段','本模型中的关系字段');
}

public function author(){
   return $this->hasOne('App\Admin\Author','id','author_id');
}

关联关系的使用方法:使用动态属性进行调用

image.png

案例:通过模型关联的一对一关系查询出每篇文章对应的作者名称


//1.一对一
public function oneOnOne(){
   $data = \App\Admin\Article::get(); //$data  Illuminate\Database\Eloquent\Collection 对象
   foreach($data as $key=>$value){    //$value Article模型对象
       echo '文章编号是:'.$value->id.';&emsp;'.'文章名称是:'.$value->article_name.';&emsp;'.'文章作者是:
       '.$value->author->author_name.'<br>';
   }
}


image.png

注意:使用模型一对一关联关系之后,其可以替代之前写的join联表操作



一对多关联关系

例如:一篇文章有多条评论

a、创建评论表:

image.png

b、创建评论模型:

class Comment extends Model
{
   //定义模型关联的数据表
   protected $table = 'comment';
   //定义主键
   protected $primaryKey = 'id';
   //定义禁止操作时间
   public $timestamps = false;
}

c、关联模型的关联方法:文章模型(主) 、评论模型(从)

需求:查询出每篇文章下所有的评论


//语法
public function 被关联的模型名小写(){
   return $this->hasMany('需要关联模型的命名空间','被关联模型的关系字段','本模型中的关系字段');
}
public function comment(){
   return $this->hasMany('App\Admin\Comment','art_id','id');
}


//2.一对多
public function oneToMore(){
   //查询数据
   $data = \App\Admin\Article::get();          //$data  Illuminate\Database\Eloquent\Collection 对象
   foreach ($data as $key=>$value){            //$value App\Admin\Article模型对象
       echo '文章编号:'.$value->id.';&emsp;'.'文章名称是:'.$value->article_name.';&emsp;'.'其下评论有:<br>';
       //$value->comment 这里的comment是模型里面的方法!!!
       foreach ($value->comment as $k=>$v){    //$v     App\Admin\Comment 模型对象
           echo '&emsp;'.$v->comment.'<br>';   //comment是字段!!!
       }
   }
}

效果:

image.png



③ 多对多关联关系

例如:一篇文章可能有多个关键词,一个关键词可能被多篇文章使用

image.png


a、建表:已经存在文章表,还需要关键词表、关键词和文章的关系表

image.png

image.png


b、创建模型:

注意:根据手册中记录的语法要求,不需要给关系表单独的创建模型


class Keyword extends Model
{
   //定义模型关联的数据表
   protected $table = 'keyword';
   //定义主键
   protected $primaryKey = 'id';
   //定义禁止操作时间
   public $timestamps = false;
}



c、查询每篇文章下的关键词

//语法
public function 被关联的模型名小写(){
   return $this->belongsToMany('需要关联模型的命名空间','多对多模型的关系表名',
       '当前模型的关系键','被关联模型的关系键');
}

注意:根据案例需求,此处的关系映射依旧写在文章模型中


//3.多对多
public function moreToMore(){
   $data = \App\Admin\Article::get();          //$data  Illuminate\Database\Eloquent\Collection 对象
   //循环输出
   foreach($data as $key=>$value){             //$value App\Admin\Article模型对象
       echo '文章编号:'.$value->id.';&emsp;'.'文章名称是:'.$value->article_name.';&emsp;'.'其所用的关键词有:<br>';
       //$value->keyword 这里的keyword是模型里面的方法!!!
       //输出全部的关键词
       foreach($value->keyword as $k=>$v){     //$v  App\Admin\Keyword模型对象
           echo '&emsp;'.$v->keyword.'<br>';   //keyword是字段!!!
       }
   }
}

效果:

image.png



3.18 项目初始化

① 下载框架


② 创建数据库,修改.env文件,配置数据库连接操作


③ 设置网站本地化为中文

a、下载语言包

b、复制下载的语言包到网站resources/lang/目录下面

c、修改配置文件config/app.php 

image.png


④ 设置时区

image.png


⑤ 清理项目(删除不需要的文件)

a、删除app/Http/Controllers/Auth目录,项目中自定义登录逻辑

image.png

b、删除database/migrations/目录下面自带的数据迁移文件

image.png

c、删除database/seeds 目录下面的默认填充器文件

image.png

d、删除resources/views 目录下的welcome.blade.php文件


e、public目录下面的css、js文件也可以删除

image.png


⑥ 关闭mysql严格模式

编辑config/database.php 文件,将strict 由true修改为false

image.png

严格模式功能说明:

不支持对not null 字段插入null值

不支持对自增字段插入 '' 值

不支持text字段有默认值


⑦ 安装debugbar工具(开发的时候可选,线上别安装)

条件:php版本>=7.0,.env环境需要设置APP_DEBUG=true  !!!

a、安装

composer require barryvdh/laravel-debugbar:~v3.3.0

b、修改配置文件config/app.php


Barryvdh\Debugbar\ServiceProvider::class,
'Debugbar' => Barryvdh\Debugbar\Facades\Debugbar::class,

效果:

image.png



3.19 其他总结

① 自定义code和msg

a、在app目录下创建common\SystemCode.php  SystemMessage.php文件

interface SystemCode{
   /*
   |--------------------------------------------------------------------------
   | 网络请求类code
   |--------------------------------------------------------------------------
   |100 + 1xx 格式,如:100101
   */
   const REQ_METHOD_ERRCODE = 100101;
   const REQ_PARAM_ERRCODE = 100102;
   const NO_PRIVILEGE_CODE = 100103;
   const TOKEN_EXPIRE_CODE = 100104;
   const FORBIDDEN_CODE =  100105;

}


/**
* 接口提示信息类
*/

interface SystemMessage{

   const REQ_METHOD_ERR = '请求方式错误';
   const REQ_PARAM_ERR = '请求参数错误';
   const NO_PRIVILEGE = '没有权限';
   const TOKEN_EXPIRE = '登录已过期';
   const FORBIDDEN = '服务器拒绝请求';
}


b、在控制器中使用code和msg

public function adminList(Request $request){
   if($request->isMethod('GET')){
       return view('admin.admin.adminlist');
   }else{
       $data = [];
       $param = ['code'=>SystemCode::REQ_METHOD_ERRCODE,'msg'=>SystemMessage::REQ_METHOD_ERR,'data'=>$data];
       return response()->json($param);
   }
}


② laravel框架使用ajax  post方式删除数据

②.① meta标签方式

a、在meta标签中添加csrf_token字段和值

<meta name="csrf-token" content="{{ csrf_token() }}">

b、删除按钮

<button type="button" class="btn btn-danger btn-md"  onclick="del(this,{{$prilist->id}});">删除</button>

c、确保ajax发送之前添加X-CSRF-TOKEN

$.ajaxSetup({

    headers: {

        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')

    }

});

d、发起服务器请求

image.png


②.② ajax 的data属性值里面传递

image.png


③ laravel框架ajax提交数据,验证错误消息返回抛出提示

image.png