官方网站:https://laravel.com/
中文官网:https://laravel-china.org/docs/laravel/5.4
composer工具
中文网址:http://www.phpcomposer.com/
composer资源仓库或应用市场
linux下设置环境变量
vi /etc/profile
# 写下以下内容
linux下设置环境变量
xxx表示你要设置的环境变量的目录名称,连接用:
xxx表示你要设置的环境变量的目录名称,连接用:
linux设置完毕后,不会马上生效
source /etc/profile
配置就是立刻生效
查看php扩展------
在windows下php的扩展
同时也要开启如下扩展 php.ini文件
extension=php_openssl.dll extension=php_pdo_mysql.dll extension=php_mbstring.dll extension=php_fileinfo.dll extension=php_curl.dll extension=php_gd2.dll extension=php_soap.dll extension=php_mysqli.dll extension=php_sockets.dll
下载好composer.phar文件后再用命令生成bat文件,composer文件需要放在php设置的环境变量目录下,bat文件也会生成在这个目录下
echo @php "%~dp0composer.phar" %*>composer.bat
切换composer镜像
因国内和国外网络访问产生的差别,所做出的选择
全局配置————在命令窗口中(windows用户)或控制台(Linux、Mac 用户)并执行如下命令
composer config -g repo.packagist composer https://packagist.phpcomposer.com
注:composer网站问题,一定要切换为国内镜像,如有条件可使用vpn
windows 7以上,mac或linux系统,一定要考虑到权限的问题。
compsoer常用命令
composer self-update //更新
更新成功,如果你要回退可以使用,如下命令退出到更新之前的版本
composer self-update --rollback //回退可以使用
创建项目
命令 composer create-project --prefer-dist laravel/laravel testproject 5.4.* # 推荐 composer create-project laravel/laravel=5.4.* --prefer-dist mylaravel
不指定版本就会下载最新版
【版本具体设置】可选
1.0.2 # 明确版本 >1.0.2 # 大于1.0.2 >=1.0.2 # 大于等于1.0.2 <1.1|>=1.2 # 小于1.1 或 大于等于1.2 1.0.* # 执行1.0.的最高版本,与<1.1等效 >1.0,<2.0 # 大于1.0 并且 小于2.0 ~1.2 # >=1.2,<2.0 ~1.2.3 # >=1.2.3,<1.3 ^1.2 # >=1.2,<2.0 ^2.3 # >=2.3,<3.0 ^3.4.6 # >=3.4.6,<4.0.0 ~3.4.6 # >=3.4.6,<3.5.0 ",逗号"代表and并且关系 "|竖杠"代表or或的关系 ^:大版限制(封顶到当前版本顶级) ~:小版限制(封顶到当前版本的次版顶级) 版本问题: 一般的软件版本有3个位数,例如2.1.4,从左到右分为1位/2位/3位 3位:小bug调试 2位:功能更新 1位:大版本更新,兼容不好
修改composer.json中添加或修改软件包或版本则可以通过此命令来更新项目。
composer update [更新指定的包名称,可选,不写更新全部]
安装指定的包——这个命令需要在项目根目录下执行
自动加在更新
如果修改了composer.json文件或删除一些文件,建议手动执行autoload命令来让项目加载文件更新。
composer dump-autoload 或 composer dump
安装命令:
composer create-project --prefer-dist laravel/laravel=5.4.* weblaravel
也可以下载离线安装包
1、app目录【重要目录】
项目的核心目录,主要用于存放核心代码,你所编写的代码绝大多数也会放到这里,如控制器、模型等。
模型也创建在这个目录下,进行手动创建分目录
2、bootstrap目录
laravel启动目录,目录包含了框架启动和自动加载设置的文件,autoload.php文件用于自动载入需要的类文件。
3、config目录【重要目录】
项目的配置目录,主要存放配置文件,比如数据库的配置。
app.php:项目主要配置文件
database.php:针对数据库的配置
4、database目录
目录包含了数据迁移及填充文件,就是使用文件的方式,来管理数据库,创建一个PHP文件,在文件中设计表结构,运行该文件,完成表的创建。
5、public目录【重要目录,主机目录】
laravel项目的web虚拟主机指定的目录,项目的入口文件和系统的静态资源目录(css,img,js,uploads)后期使用的外部静态文件(js、css、图片等)都需要放到Public目录下。
7、routes目录【重要目录】
定义路由的目录,laravel中所有的访问请求,都必须事先定义好路由,web.php是定义路由的文件。
8、storage目录
主要是存放缓存文件和日志文件,注意,如果在【linux】环境下,该目录需要有【可写】权限。
9、vendor目录
主要是存放第三方的类库文件,laravel思想主要是共同的开发,不要重复的造轮子(例如里面可能存在验证码类,上传类,邮件类),该目录还存放laravel框架的源码,注意如果要使用composer软件管理的,composer下载的类库都是存放在该目录下面的。
10、env文件【重要文件】
主要是设置一些系统相关的环境配置文件信息。config目录里面的文件配置内容一般都是读取该文件里面的配置信息(config里面的配置项的值基本都是来自.env文件)。
11、artisan脚手架文件
主要用于生成的代码的(自动生成),比如生成控制器,模型文件等。
执行命令:php artisan 需要执行的指令
执行此命令有2点要求
(1)、php必须添加环境变量,并且保证版本能是laravel所要求的版本。
(2)、执行命令时,注册artisan文件必须存在当前命令路径下。
12、composer.json【重要文件】
依赖包配置文件声明当前需要的软件依赖,但是不能删除,composer需要使用。
语法:标准JSON文件
需要重点掌握的目录【重点】
目录 | 功能 |
---|---|
app | 项目的核心目录,主要用于存放核心代码 |
app/Http/Controllers | 控制器目录 |
app/Http/Models | 模型目录【非默认,自定义创建的】 |
resources/views | 视图目录 |
config | 配置文件目录 注意/.env来配置 |
routes | 路由文件目录 |
data/migrations | 迁移文件目录(操作数据表结构) |
data/seeds | 数据种子目录(模拟测试数据) |
php artisan serve这是临时运行命令,关闭命令窗口后就会失效 或指定端口来运行 php artisan serve --port=9090 原则是让我们的端口不要产生冲突,如有冲突,启动服务就会失败
Apachel配置虚拟主机和修改本机hosts文件,hosts文件自己配,完后重启
# 设置虚拟主机 <VirtualHost *:80> # 设置网站目录 laravel指向到public目录下面 DocumentRoot "F:/www/class/qz06/web/public" # 设置网站域名 ServerName www.qz06.com # 错误日志 ErrorLog "F:/www/logs/www.qz06.com_error.log" # 成功日志 CustomLog "F:/www/logs/www.qz06.com_access.log" combined # 设置目录访问权限 <Directory "F:/www/class/qz06/web/public"> # 指定目录启用特怀 Options Indexes FollowSymLinks # 是否允许使用.htaccess文件 AllowOverride All # 访问目录权限 允许所以有人来访问 Require all granted </Directory> </VirtualHost>
路由文件的位置:项目目录/routes/web.php文件
①、路由定义格式
Route::请求方式('url',匿名函数); Route::请求方式('url','控制器名称@操作方法');
注:laravel默认是给我们的post提交进行了csrf验证,所以测试的时候,可以进行关闭
GET(SELECT):从服务器取出资源(一项或多项)。 POST(INSERT):在服务器新建一个资源。 PUT/PATCH(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 DELETE(DELETE):从服务器删除资源。
在laravel中也可以这样定义路由请求方式
Route::get($uri, $callback); Route::post($uri, $callback); Route::put($uri, $callback); Route::delete($uri, $callback);
有的时候可能需要注册一个可响应多个 HTTP 方法的路由,这时可以使用 match 方法,也可以使用 any 方法注册一个实现响应所有 HTTP 的请求的路由:
# 支持 get和post请求 Route::match(['get', 'post'], '/', $callback); # 支持所有类型的请求 (不建议用它) Route::any('foo',$callback);
路由参数主要针对的是GET请求的情况,语法格式如下:
# 必填 Route::get('URL/{参数名称}','闭包函数或控制器响应方法标识'); # 可选 Route::get('URL/{参数名称?}','闭包函数或控制器响应方法标识'); # 参数限制 Route::get('URL/{参数名称}','闭包函数或控制器响应方法标识')->where('参数名称','正则表达式'); Route::get('URL/{参数名称}','闭包函数或控制器响应方法标识')->where(['参数名称'=>'正则表达式']);
where('参数名称','正则表达式')用来对输入的参数进行限制,只有符合正则表达式要求的参数才可以传递
路由别名相当于在路由定义的时候,为路由起了一个别名,在以后的程序中可以通过这个别名来获取路由的信息,用法:
Route::get('/user/{id}',function($id){ return "当前用户id是:" . $id; }) -> name('名字'); # 生成了对应的URL地址 $url = route('profile');
路由前缀
使用prefix属性指定路由前缀,就是把可以归纳在一起的路由放在一起
Route::group(['prefix' => 'admin'], function () { Route::get('users', function () { // 匹配 "/admin/users" URL }); });
查看定义好的路由:
php artisan route:list
控制器文件命名和创建
使用大驼峰命名,同时注意命名空间和基类控制器的引入
创建方式:cmd方式 进入到artisan文件所在的目录
php artisan make:controller TestController
控制器路由
路由设置格式基本相同,只是将闭包函数换成‘控制器类名@方法名’
定义格式如下:
Route::请求方法(URL,'控制器类名@方法名')
控制器分目录
php artisan make:controller 目录名称/控制器文件名 php artisan make:controller Home/UserController #分完目录的控制器如何来定义路由呢 // 分目录 Route::get('home/user/index','Home\UserController@index');
分目录路由定义
web.php路由文件的定义
获取客户端的数据
接收用户输入的类:Illuminate\Support\Facades\Input
Facades为应用程序的服务容器中可用的类提供了一个「静态」接口。Laravel 自带了很多 facades ,几乎可以用来访问到 Laravel 中所有的服务。Facades 有很多好处,它为我们使用 Laravel 的各种功能提供了简单,易记的语法,让你不需要记住长长的类名来放进入类的引入。
Input::get('参数的名字', ['如果参数没有被传递使用该默认值']) Input::all(): 获取所有的用户的输入 Input::only([]): 获取指定几个用户的输入 Input::except([]): 获取指定几个用户的输入以外的所有的参数 Input::has('名称'):判断某个输入的参数是否存在 上述方法即既可以获取get中的信息,也可以获取post中信息。
①、在app.php文件中添加facades
就是将这段代码添加进去('Input' => Illuminate\Support\Facades\Input ::class,)
类:Illuminate\Http\Request
使用依赖注入到方法中去使用。
依赖注入是一种软件设计思想,在传统软件中,上层代码依赖于下层代码,当下层代码有所改动时,上层代码也要相应进行改动,因此维护成本较高。而依赖注入原则的思想是,上层不应该依赖下层,应依赖接口。意为上层代码定义接口,下层代码实现该接口,从而使得下层依赖于上层接口,降低耦合度,提高系统弹性
// 获取请求方式 GET POST等 dump($request->method()); // 检测方法 是否是POST提交 dump($request->isMethod('post')); // 获取完整URL dump($request->url()); // 获取客户端IP dump($request->ip()); // 获取端口 dump($request->getPort()); // 获取参数 dump($request->get('name')); dump($request-> get ('name','没有值')); // 检测是否存在 dump($request->has('name')); // 获取所有值 dump($request->all()); // 获取部份值 dump($request->only(['name','age'])); // 获取排除以外的值 dump($request->except(['_token'])); // 获取头信息 dump($request->header('User-Agent'));
控制器
php artisan make:controller IntestController
所有路由和控制器都会返回一个响应并返回给用户的浏览器。可以使用提供的助手函数 response()来进行操作,当然也可以使用类(Illuminate\Http\Response)来操作。
1、返回字符串
在控制器或路由中 echo 或 return 一个字符串就可以了
2、附加头信息
写入头信息一定要有主体信息
return response('')->header('Myheader','wuchen');
3、设置cookie
laravel框架为了安全,它的cookie是加密的,laravel的 cookie加密是可逆的
# 设置cookie return response('')->cookie('id',111,10,'/'); ##cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly) # 读取cookie echo $request->cookie('id');
4、获取cookie
5,重定向
return redirect('路由'); # 路由别名 return redirect()->route('路由别名'); // 页面跳转 //return redirect('index'); # 推荐写法 //return redirect(route('testindex')); # 路由别名 testindex //return redirect()->to(route('testindex')); # 路由别名 testindex //return redirect()->route('testindex'); # 路由别名 testindex
6、json数据返回
json 方法会自动将 Content-Type 响应头信息设置为 application/json,并使用 PHP 的 json_encode 函数将数组转换为 JSON 字符串。
return response()->json([ 'name' => 'zhangsan', 'age' => 22 ]);
控制器
json方法参数2为http状态码,此状态码在进行接口编写时,将要进行设置
如果访问方法或数据不存在,返回 404
成功返回 200
7、文件下载
用于生成强制让用户的浏览器下载指定路径文件的响应。
return response()->download('./robots.txt');
位置:resources/views
(1)文件名小写
(2)文件名的后缀是 .blade.php
因为laravel里面有一套模板引擎就是使用blade,可以直接使用标签语法{{ $变量名 }}, 当然也可以使用原生的php语法显示数据
语法:
view(模板文件名称,关联数组) view(模板文件名称,compact('变量名1','变量名2')) view(模板文件名称)->with(名称,值)->with(名称,值) view(模板文件名称)->with(关联数组)
①、变量
{{$变量名}} 例 {{$name}}等价于<?php echo $name?> 或 <?= $name; ?>
②、三元运算
{{ $name or 'Default' }} 等价于<?php echo isset( $name)?$name:'default'?>
③、未转义输出
一般用于富文本编辑器添加的内容显示所用
如果变量信息里边如果有 ”<” ”>” 等html标记信息,那么该变量在输出的时候也会看到该标记,即html标记被转化为符号实体了,而没有被浏览器解析掉,如果希望看到被浏览器解析后的内容,就需要设置两个感叹号。
例如:
{!!$变量!!} $title = "<a href='http://www.baidu.com'>百度</a>";
④、原始形态输出
由于很多 JavaScript 框架都使用花括号来表明所提供的表达式,所以你可以使用 @ 符号来告知 Blade 渲染引擎你需要保留这个表达式原始形态态输
<h1>Laravel</h1> Hello, @{{ $变量名 }}
⑤、注释
{{-- 这里的内容不会显示 --}}
可以在blade模板中直接使用php函数
{{php函数名()}}
@if (count($records) === 1) 我有一条记录! @elseif (count($records) > 1) 我有多条记录! @else 我没有任何记录! @endif
@for ($i = 0; $i < 10; $i++) 目前的值为 {{ $i }} @endfor @foreach ($users as $user) <p>此用户为 {{ $user->id }}</p> # 如果传过来的就是数据那么我们就用 <p>{{ $user['id'] }}</p> @endforeach @forelse ($users as $user) <li>{{ $user->name }}</li> # 如果传过来的就是数据那么我们就用 <p>{{ $user['id'] }}</p> @empty <p>没有用户</p> @endforelse
注:foreach有循环变量,,loop->index 当前循环所迭代的索引,起始为 0。
视图名称直接从resources/views后边开始设置即可
一个项目系统里边有许多视图文件,因此要在resources/views目录下创建二级、三级等目录,进行管理不同的视图文件,需要手动去创建对应的目录。
引入二级、三级视图文件:
return view(目录1.目录2.名称); return view(目录1/目录2/名称);
比如视图文件;
resources/views/add.blade.php 则使用函数return view(add); resources/views/admin/index.blade.php 则使用函数return view(admin.index); resources/views/admin/goods/index.blade.php 则使用函数return view(admin.goods.index);
在一个项目中有许多模板文件,它们有一个特点:拥有共同的头部 和 脚部内容
为了避免相同代码重复开发、维护 造成工作效率低下
可以把共同的头部和脚部内容集中到一个布局文件中,之后各个具体模板文件去继承该布局文件而使用头部和脚步内容。这个过程成为模板继承。
布局文件中相同的代码只维护一份,会大大提升项目开发效率
@extends('laoyouts.home') #表示继承resources/views/layouts/home.blade.php布局文件 使用section标签替换布局模板中可变区域; @section('content') 给布局文件yield('content ')的区域进行填充的内容 @endsection
用法
@include('public.header') # public 表示 views下面的public目录 # header 表示在views/public/header.blade.php文件
在写页面肯定会引入相关的外部文件(js、css、image),则会涉及到路径的问题。
引入静态文件
{{ asset('静态资源') }}
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。
是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行
可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI......而现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”
Laravel 自动为每一个被应用管理的有效用户会话生成一个 CSRF “令牌”,该令牌用于验证授权用户和发起请求者是否是同一个人。
csrf在laravel框架中的使用,就是在客户端form表单中设置一个_token表单域
同时把该表单域的值记录给session,提交表单给服务器的后,服务器判断form表单中的token与session中的token是否一致,一致就进行正常的后续处理,否则该表单非法并舍弃之。
larave生成csrf方式
在laravel有方便的方式可以生成该_token表单域:
{{ csrf_field() }} 生成一个完整的Input框 {{ csrf_token() }} 生成一个token值 # csrf_field 使用 <form method="POST" action="/profile"> {{ csrf_field() }} ... </form> <input type="hidden" name="_token" value="{{ csrf_token() }}">
并不是所有请求都需要避免CSRF攻击,比如去第三方API获取数据的请求。
可以通过在VerifyCsrfToken(app/Http/Middleware/VerifyCsrfToken.php)中间件中将要排除的请求URL添加到$except属性数组中。
1、支持的数据库类型
MySQL
Postgresql
SQLite
SQL Server
在laravel中修改连接数据库的文件有两处
修改 .env文件 【推荐】
修改 config/database.php文件。
建议大家日后在配置数据的时候,修改 .env 连接mysql数据库的参数。 .env文件中的参数值可以通过 【env()】函数来进行读取。
laravel中的DB类为我们提供了两个形式来操作数据库
原生sql语句操作数据库
构建器操作数据库
配置好数据库连接以后,DB类为我们提供select、update、insert、delete等方法,方便我们来操作执行sql语句
添加操作(insert)
// 添加操作 $ret = DB::insert('insert into test_member (name,age,email) values (:name,:age,:email)', [':name'=>'张三',':age'=>20,':email'=>'admin@admin.com']); var_dump($ret); # 添加成功返回为true,否则为false
修改操作(update)
// 修改操作 $ret = DB::update('update test_member set age=:age where id=:id', [':age' => 12, ':id' => 1]); dd($ret);
删除操作(delete);
// 删除操作 #$ret = DB::delete("delete from test_member where id=:id",[':id'=>1]); dd($ret);
查询操作(select);
// 查询 select $ret = DB::select("select * from web64_user"); $ret = DB::select("select * from web64_user where id>=:id",[':id'=>$id]); dump($ret);
Laravel 的数据库查询构造器提供了一个方便、流畅的接口,用来创建及运行数据库查询语句。它能用来执行应用程序中的大部分数据库操作,且能在所有被支持的数据库系统中使用。
Laravel 的查询构造器使用 PDO 参数绑定,来保护你的应用程序免受 SQL 注入的攻击
①、查询数据操作
table(表名),这里的表名,如查有前缀不用写。
(一)、查询多条记录(get)
// 查询多条无条件 // 查询所有 $data = DB::table('user')->get(); // 查询所有,并指定字段 推荐使第一种方式 $data = DB::table('user')->get(['name','age']); // 获取ID大于5的数据 $ret = DB::table('member')->where('id','>=',5)->get(); dd($ret);
(二)、查询单条记当(first)
// 查询单条数据 $ret = DB::table('member')->where('id', 5)->first(); dd($ret);
(三)、获取某个具体的值(value)
// 获取某个具体的值 $ret = DB::table('member')->where('id',5)->value('name'); dd($ret);
(四)、获取一列数据(pluck)
// 获取一列数据 $ret = DB::table('member')->pluck('name');
(五)、排序操作(orderBy)
// 排序 以ID来进行倒序排列 $ret = DB::table('member')->orderBy('id','desc')->get(); dd($ret);
(六)、总条目数
# 总条目数 echo 'count: '; echo DB::table('member')->count();
(七)、分页操作
// 分页操作 $ret = DB::table('member')->orderBy('id','desc')->offset(0)->limit(2)->get(); dd($ret);
limit:表示限制输出的条数
offset:从什么地方开始,起始从0开始
②、添加数据操作(insert/ insertGetId)
对数据库中的某个表增加数据主要有两个函数可以实现,分别是insert()和insertGetId()
如果数据表有自增 ID,使用 insertGetId 方法来插入记录并返回 ID 值:
注:当使用 PostgresSQL 时 insertGetId 方法默认自增列被命名为 id,如果你想要从其他“序列”获取 ID,可以将序列名作为第二个参数传递 到 insertGetId 方法
insert() 可以同时添加一条或多条,返回值是布尔类型。 insertGetId() 只能添加一条数据,返回自增的id。
insert方法可以一次插入一条也可一次插入多条
③、修改数据(update)
查询构建器还可以通过使用 update 方法更新已有记录。update 方法和 insert 方法一样,接收字段名和字段值的键 值对数组,对应字段名就是要更新的列,你可以通过 where 子句来对 update 查询进行约束:
DB::table('users') ->where('id', 1) ->update(['votes' => 1]);
更新 JSON 字段的时候,需要使用 -> 语法访问 JSON 对象上相应的值,该操作只能用于支持 JSON 字段类型的数据库:
DB::table('users') ->where('id', 1) ->update(['options->enabled' => true]);
增加/减少
查询构建器还为增减给定字段名对应数值提供方便。相较于编写 update 语句,这是一条捷径,提供了更好的体验和测试接口。 这两个方法都至少接收一个参数:需要修改的列。第二个参数是可选的,用于控制列值增加/减少的数目。
DB::table('users')->increment('votes'); DB::table('users')->increment('votes', 5); DB::table('users')->decrement('votes'); DB::table('users')->decrement('votes', 5);
在操作过程中你还可以指定额外的列进行更新:
DB::table('users')->increment('votes', 1, ['name' => 'John']);
④、删除数据(delete)
查询构建器还可以通过 delete 方法从表中删除记录,你可以在调用 delete 方法前通过添加 where 子句来添加约束条件:
DB::table('users')->delete(); DB::table('users')->where('votes', '>', 100)->delete(); 注:删除操作一定要写条件,否则后台很严重
如果你希望清除整张表,也就是删除所有列并将自增 ID 置为 0,可以使用 truncate 方法
DB::table('users')->truncate();
悲观锁 & 乐观锁 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这 个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此 期间别人有没有去更新这个数据,可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似 于 write_condition 机制的其实都是提供的乐观锁。 下面我们看下悲观锁和乐观锁在 Laravel 中的使用:
悲观锁使用 Laravel 查询构建器提供了一些方法帮助你在 select 语句中实现“悲观锁”。可以在查询中使用 sharedLock 方法从而在运行语句时带一把”共享锁“。 共享锁可以避免被选择的行被修改直到事务提交: DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); 上面这个查询等价于下面这条 SQL 语句
select * from users
where votes
> '100' lock in share mode 此外你还可以使用 lockForUpdate 方法。“for update”锁避免选择行被其它共享锁修改或删除: DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); 上面这个查询等价于下面这条 SQL 语句: select * from users
where votes
> '100' for update for update 与 lock in share mode 都是用于确保被选中的记录值不能被其它事务更新(上锁),两者的区别在于 lock in share mode 不会阻塞 其它事务读取被锁定行记录的值,而 for update 会阻塞其他锁定性读对锁定行的读取(非锁定性读仍然可以读取这些记录,lock in share mode 和 for update 都是锁定性读)。 这么说比较抽象,我们举个计数器的例子:在一条语句中读取一个值,然后在另一条语句中更新这个值。使用 lock in share mode 的话可以允许 两个事务读取相同的初始化值,所以执行两个事务之后最终计数器的值+1;而如果使用 for update 的话,会锁定第二个事务对记录值的读取直到第 一个事务执行完成,这样计数器的最终结果就是+2 了。 乐观锁使用 乐观锁,大多是基于数据版本 ( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般 是通过为数据库表增加一个 “version” 字段来实现。 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对, 如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 总结 两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了 系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
表单验证是为了防止跳过客户端验证而造成的系统安全问题,一但非法用户绕过客户端验证而服务器端没有加以验证,这样就是很不安全了,所以项目必须要进行服务器端表单验证。
Laravel 提供了多种不同的验证方法来对应用程序传入的数据进行验证。
规则名 | 说明 |
---|---|
required | 不能为空 |
max:value | 字段值必须小于或等于value,对于字符串来说,value 为字符数 |
min:value | 字段值必须大于或等于value,对于字符串来说,value 为字符数 |
验证邮箱是否合法 | |
url | 验证字段必需是有效的 URL 格式 |
confirmed | 验证两个字段是否相同,如果验证的字段是password,则必须输入一个与之匹配的password_confirmation字段 |
integer | 验证字段必须是整型 |
ip | 验证字段必须是IP地址 |
numeric | 验证字段必须是数值 |
size:value | value 验证字段必须有和给定值value想匹配的尺寸,对字符串而言,value是相应的字符数目,对数值而言,value是给定整型值;对文件而言,value是相应的文件字节数 |
string | 验证字段必须是字符串 |
unique | 表名,字段,需要排除的ID |
between:min,max | 验证字段值的大小是否介于指定的 min 和 max 之间。字符串、数值或是文件大小的计算方式和 size 规则相同 |
regex:pattern | 验证字段值是否符合指定的正则表达式 |
注:多个验证规则可以通过 "|" 字符进行隔开
使用php文件编写的代码来进行,数据库中的表结构的创建和修改。
命令
php artisan make:migration create_test_table --create=test make:migration 参数 create_test_table 生成的文件后缀名称 --create=test 生成一个表名为test的数据表
执行创建迁移文件命令
编写迁移文件
创建好的文件会,有up和down两个方法,up 生成表所执行的方法,down 删除表所执行的方法。
使用 migrate Artisan 命令,来运行所有未运行过的迁移:
php artisan migrate
回滚最后一次的迁移操作, 删除(回滚)之后会删除迁移记录,并且数据表也会删除,但是迁移文件依旧存在,方便后期继续迁移(创建数据表)。
php artisan migrate:rollback # 直接执行了迁移文件中的 down方法
php artisan migrate:refresh 先执行所有的迁移文件的down方法,再执行所有的迁移文件的up方法
填充操作就是往数据表中写测试数据的操作。数据库填充文件一般放置在,项目/database/seeds目录下,该文件以一个类的形式创建,类名可以任意取,不过一般约定为数据表名后加上【TableSeeder】,需要注意的是,文件名与类名相同,否则无法自动加载类。
php artisan make:seeder TestTableSeeder
php artisan db:seed --class=需要执行的种子文件名 php artisan db:seed
清除表并执行迁移执行填充文件
php artisan migrate:refresh --seed
Laravel 自带的 Eloquent ORM 提供了一个美观、简单的与数据库打交道的 ActiveRecord 实现,每张数据表都对应一个与该表进行交互的“Model模型”,模型允许你在表中进行数据查询,以及插入、更新、删除等操作。
命名规则
本身laravel对模型的命名没有严格的要求,一般采用 表名(首字母大写).php
如: Member.php User.php Admin.php Goods.php
使用artisan命令
php artisan make:model 模型文件名 # 分目录的 php artisan make:model Models/Member # 创建模板并生成迁移文件 php artisan make:model Models/Article –m -m 生成迁移文件
(1)、定义表名($table)
模型所对应的默认表名是在模型后面加【s】,如同表名没有s则操作的时候就会报错。
解决方案
// 指定表名 protected $table = 'member';
(2)、指定主键名($primaryKey)
laravel中默认的主键ID名为id,如果你创建的表字段中主键ID的名称不为id,则需要通过 $primaryKey 来指定一下。
主键 Eloquent 默认每张表的主键名为 id,你可以在模型类中定义一个 属性来覆盖该约定。此外,默认主键字段是自增的整型数据,这意味着主键将会被自动转化为类型,如果你想要使用非自增或非数字类型主键,必须在对应模型中设置incrementing 属性为 false,如果主键不是整型,还要设置 属性值为。时间戳默认情况下,期望和已经存在于数据表中,如果你不想要这些自动管理的数据列,在模型类中设置timestamps 属性为 false:
如果你需要自定义时间戳格式,设置模型中的 $dateFormat 属性。该属性决定日期被如何存储到数据库中,以及模型被序列化为数组或 JSON 时日 期的格式:
(3)、指定时间戳($timestamps)
默认情况下,模型操作会认为在你的数据库表有 created_at 和 updated_at 字段。如果你不希望让模型来自动维护这两个字段,可在模型内将 $timestamps 属性设置为 false。
// 时间戳 这里一定要注意它是用的public public $timestamps = false;
(4)、批量赋值(与guarded)
当通过create方法来保存数据的时候,你需要先在你的模型上定义或guarded属性。
// 批量赋值 # 白名单 protected $fillable = ['允许添加的字段名']; # 黑名单 protected $guarded = ['拒绝添加的字段名'];
# 方法一 save() # 对象属性方式 # 方法二 create() # 数组方式 需要在模型中设置好fillable或guarded属性 # 方法三 insert() #数组方式
save 方法还可以用于更新数据库中已存在的模型。要更新一个模型,应该先获取它,设置你想要更新的属性,然后调用 save 方法。同样, updated_at 时间戳会被自动更新,所以没必要手动设置其值
$flight = App\Flight::find(1); $flight->name = 'New Flight Name'; $flight->save();
# 方法一 save() # 对象属性方式 # 方法二 update() # 数组
批量更新 更新操作还可以同时修改给定查询提供的多个模型实例
App\Flight::where('active', 1) ->where('destination', 'San Diego') ->update(['delayed' => 1]);
update 方法要求以数组形式传递键值对参数,代表着数据表中应该被更新的列。 注:通过 Eloquent 进行批量更新时,saved 和 updated 模型事件将不会在更新模型时触发。这是因为在进行批量更新时并没有从数据库获取模型
# 查询单条 first() # 查询多条 get() # 条件 where() # 排序 orderBy() # 取指定的值 value() # 取指定的列 pluck() # 查询总记录数 count()
注意:在laravel里面如果要删除数据,必须先根据条件查询出对应的记录,返回一个对象,然后调用对象的delete方法即可。
# 删除 一定要指定条件删除 delete()
在laravel里面要完成分页是很简单的,laravel是直接调用模型的分页方法,返回对应的数据和分页的字符串。
# 模型 # 标准分页 分页的页码数 Model::paginate(每页显示的记录数) # 简单分页 只有上一页和下一页 Model::simplePaginate(每页显示的记录数) # 模板 {{ $model->links() }}
由于 HTTP 是无状态的,Session 提供了一种在多个请求之间存储有关用户信息的方法,laravel给我们提供了操作session的相关类来方便我们的使用。
laravel中的session默认存到文件中
session文件的目录:storage\framework\sessions
操作session的方法在laravel中有好几种方案,有类来操作也有利用辅助函数来操作。
Session类来操作
辅助函数来操作 session()
// 写入session // 方法一 Session::put('键名','值'); // 方法二 辅助函数 关联数组 推荐写法 session(['键名'=>'值']); 注:辅助函数存储session的时候一定要以数组的形式来定义。
// 读取session // 方法一 Session类 dump(Session::get('session名称',[默认值])); // 方法二 辅助函数 dump(session(' session名称')); // 读取全部的session var_dump(Session::all()); var_dump(session()->all());
// 方法一 var_dump(Session::has('session名称')); // 方法二 var_dump(session()->has(' session名称'));
退出时使用
// 删除Session // 方法一 Session::forget(' session名称'); if (!Session::has(' session名称')){ echo 'name1:已被删除掉<hr>'; } // 方法二 session()->forget(' session名称'); if (!session()->has(' session名称')){ echo 'name2:已被删除掉<hr>'; } ------------------------------------------------- // 删除全部的session数据 // 方法一 Session::flush(); // 方法二 session()->flush();
使用这个方法保存 session,只能将数据保留到下个 HTTP 请求,然后就会被自动删除。
// 方法一 Session::flash('msg','你好世界'); var_dump(session('msg')); // 方法二 session()->flash('msg','你好世界'); var_dump(session('msg'));
中间件作为请求和响应之间的中间人。它是一种过滤机制类型。例如,Laravel包括一个中间件用来验证应用程序的用户认证与否。如果用户通过验证,它将被重定向到主页,否则将被重定向到登录页面。
中间件可以通过执行以下命令来创建,所有的中间件都位于app/Http/Middleware目录。
php artisan make:middleware 中间件名
php artisan make:middleware CheckLogin
这个命令会在app/Http/Middleware目录下创建一个新的中间件类CheckLogin类
中间件分三类,分别是全局中间件、中间件组和指定路由中间件
全局中间件 如果你想要定义的中间件在每一个 HTTP 请求时都被执行,只需要将相应的中间件类添加到 app/Http/Kernel.php 的数组属性 $middleware 中即可:但除非真的需要,否则我们一般不会把业务级别的中间件放到全局中间件中。
该文件包含两个属性: 和routeMiddleware。属性用于注册全局中间件,routeMiddleware属性用于注册路由指定中间件。
分配中间件到指定路由 如果你想要分配中间件到指定路由,首先应该在 app/Http/Kernel.php 文件中分配给该中间件一个 key,默认情况下,该类 的 $routeMiddleware 属性包含了 Laravel 自带的中间件,要添加你自己的中间件,只需要将其追加到后面并为其分配一个 key,例如:
// 在 App\Http\Kernel 类中... /** * 应用的路由中间件列表 * * 这些中间件可以分配给路由组或者单个路由 * * @var array */ protected $routeMiddleware = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'token' => CheckToken::class ];
中间件在 HTTP Kernel 中被定义后,可以使用 middleware 方法将其分配到路由:
Route::get('/', function () { // })->middleware('token');
通过 Composer 安装 Captcha 扩展包:
composer require mews/captcha # 注: 它需要你开启 gd2 mbstring fileinfo等php的扩展
使用Captcha服务提供者之前还需要在config/app.php中注册服务提供者:
'providers' => [ … # 在服务提供者中添加此项 Mews\Captcha\CaptchaServiceProvider::class, ]
同时注册下相应门面:
'aliases' => [ // ... 'Captcha' => Mews\Captcha\Facades\Captcha::class, ]
如果要使用自定义的配置,还可以发布配置文件到config目录:
php artisan vendor:publish
常用方法
# 返回url {!! captcha_src() !!} # 返回 img 的html {!! captcha_img () !!}
Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于 config/cache.php。在该文件中你可以指定在应用中默认使用哪个缓存驱动。Laravel 目前支持主流的缓存后端如 Memcached 和 Redis 等,默认是使用文件缓存。
# 添加 如果key不存在则添加成功,如果key存在,返回false Cache::add('key', 'value', $minutes); # 设置 不管key值是否存,都可以设置成功 Cache::put('key', 'value', $minutes); # 设置永久缓存 Cache::forever('key', 'value');
$value = Cache::get('key'); $value = Cache::get('key', 'default'); $value = Cache::get('key', function(){});
# 检查缓存的key值是否存在,存在返回true否则返回false Cache::has('key')
# 先获取再删除 $value = Cache::pull('key'); # 删除单个 Cache::forget('key'); # 清除所有的缓存 Cache::flush();
有时候可能想要获取缓存项,但如果请求的缓存项不存在时给它存储一个默认值。例如,可能想要从缓存中获取所有用户,或者如果它们不存在的话,从数据库获取它们并将其添加到缓存中,可以通过使用 Cache::remember 方法实现。
$value = Cache::remember('users', $minutes, function () { return 'key不存的时候返回的数据'; });
在laravel里面实现文件的上传是很简单的,不用引入第三方的类库,直接通过Request对象就可以获取到上传文件资源后进行保存。
# 获取上传的文件 $file = $request->file('文件表单名称'); # 验证文件是否存在 $request->hasFile('文件表单名称'); # 验证文件是否上传成功 $request->file('文件表单名称')->isValid() # 返回上传文件的扩展名称 $ext = $file->getClientOriginalExtension() # 返回上传文件的真实名称 $file->getClientOriginalName() # 返回上传文件的大小 $file->getClientSize() #将文件移动到服务器指定的位置 $file->move(路径,文件名)
数据表之间经常会互相进行关联。例如,一篇博客文章可能会有多条评论,或是一张订单可能对应一个下单客户。Laravel中的ORM让管理和处理这些关联变得很容易。
在实际的项目中我们保存用户的信息往往进行分表来进行保存,把常用的基础数据存放在一张表中,而一些不用常的冷数据存放在另一张表中,而这2张表的关系就为一对一的关系。
模型中使用 $this->hasOne(关联model,[关联model的联系键],[本model的联系键]); return $this->hasOne(Extuser::class, 'uid', 'id'); # 关联表中的外键名 user_id 本表中的主键ID为id return $this->hasOne(Extuser::class);
在实际的项目中一个用户发表多篇的文章,这样的关系就是一对多的关系。
//模型中使用 $this->hasMany(关联model,[关联model的联系键],[本model的联系键]); return $this->hasMany(App\Phone::class, 'foreign_key', 'local_key');
一个用户对应着多的权限,一个权限也对应多个用户,这样两者的关系就为多对多的关系,一般在做后台用户权限的时候会用涉及到。
//模型中使用 $this-> belongsToMany(关联表model,中间表表名,中间表中本model的关联ID,中间表中关联model的关联ID); return $this->belongsToMany(App\User::class, 'user_auth_table', 'user_id', 'auth_id');
Redis 是一款开源且先进的键值对数据库。由于它的键指向的数据包含了 字符串、哈希、列表、集合 和 有序集合 这些数据类型,因此常被用作数据结构服务器。
composer require predis/predis
应用程序的 Redis 配置都在 config/database.php
配置文件中。在这个文件里,可以看到 redis
数组里面包含了应用程序使用的 Redis 服务器:
默认的服务器配置对于开发来说应该足够了。可以根据使用的环境来随意更改数组。只需给每个 Redis 服务器指定名称、host 和 port 即可。
默认情况下,Redis 服务会提供 16 个数据库,Laravel 使用数据库 0
(请见 Redis 文档)作为缓存和 Session 的存储。
在执行命令 php artisan cache:clear
清除缓存时,会把 Session 也连带清除了,可以通过以下设置来避免这个问题。
我们的目的是让缓存,也就是默认的 Redis 存储到 0 号数据库,Session 存储在 1 号数据库。
修改 config/database.php
,在 redis
选项内增加 session
选项,并把 database
修改为 1:
'redis' => [ 'cluster' => false, 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], 'session' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 1, ], ],
修改 config/session.php
,把下面这一行:
'connection' => null,
改为:
'connection' => 'session',
修改 .env
文件的 SESSION_DRIVER
选项为 redis,开始应用上。
SESSION_DRIVER=redis
执行以下命令后检查下是否退出登录:
php artisan cache:clear
如果不会就大功告成了。