All posts by 龙生
基础组件 —— URL 生成
简介 Laravel 提供了多个辅助函数来帮助我们在应用中生成 URL。这些函数主要用于在视图模板和 API 响应中构建链接,或者生成重定向响应。 快速入门 生成 URL url 辅助函数可用于为应用生成任意 URL,并且生成的 URL 会自动使用当前请求的 scheme(HTTP or HTTPS) 和 host 属性:
1 2 3 4 5 6 |
$post = App\Post::find(1); echo url("/posts/{$post->id}"); // 输出 http://example.com/posts/1 |
访问当前 URL 如果没有传递路径信息给 url 辅助函数,则会返回一个 Illuminate\Routing\UrlGenerator 实例,从而允许你访问当前 URL 的信息:
1 2 3 4 5 6 7 8 9 |
// 获取不带请求字符串的当前 URL... echo url()->current(); // 获取包含请求字符串的当前 URL... echo url()->full(); // 获取上一个请求的完整 URL... echo url()->previous(); |
上述每一个方法都可以通过 URL 门面进行访问,例如:
1 2 3 4 |
use Illuminate\Support\Facades\URL; echo URL::current(); |
命名路由 URL route 可用于生成指向命名路由的 URL。命名路由允许你生成不与路由中定义的实际 URL 耦合的 URL,因此,当路由的 URL 改变了,route 函数调用不需要做任何更改。例如,假设你的应用包含一个定义如下的路由:
1 2 3 4 |
Route::get('/post/{post}', function () { // })->name('post.show'); |
要生成指向该路由的 URL,可以这样使用 route 辅助函数:
1 2 3 4 |
echo route('post.show', ['post' => 1]); // 输出 http://example.com/post/1 |
通常我们会使用 Eloquent 模型的主键来生成 URL,因此,可以传递 Eloquent 模型作为参数值,route 辅助函数会自动解析模型主键值,所以,上述方法还可以这么调用:
1 2 |
echo route('post.show', ['post' => $post]); |
控制器动作 URL action 辅助函数用于为控制器动作生成 URL,和路由中的定义一样,你不需要传递完整的控制器命名空间,却而代之地,传递相对于App\Http\Controllers 命名空间的控制器类名即可:
1 2 |
$url = action('HomeController@index'); |
如果控制器方法接收路由参数,你可以将其作为第二个参数传递给该方法:
1 2 |
$url = action('UserController@profile', ['id' => 1]); |
参数默认值 对某些应用而言,你可能希望为特定 URL 参数指定请求默认值,例如,假设多个路由都定义了一个 {locale} 变量:
1 2 3 4 |
Route::get('/{locale}/posts', function () { // })->name('post.index'); |
每次调用 route 辅助函数都要传递 locale 变量显得很笨拙,所以,我们可以在当前请求中使用 URL::defaults 方法为这个参数定义一个默认值,我们可以在某个路由中间件中调用该方法以便可以访问当前请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\URL; class SetDefaultLocaleForUrls { public function handle($request, Closure $next) { URL::defaults(['locale' => $request->user()->locale]); return $next($request); } } |
一旦设置好 locale 参数的默认值之后,就不必在通过 route 辅助函数生成 URL 时每次指定传递的值了。 from:http://laravelacademy.org/post/8787.html
View Details基础组件 —— Blade 模板引擎
简介 Blade 是由 Laravel 提供的非常简单但功能强大的模板引擎,不同于其他流行的 PHP 模板引擎,Blade 在视图中并不约束你使用 PHP 原生代码。所有的 Blade 视图最终都会被编译成原生 PHP 代码并缓存起来直到被修改,这意味着对应用的性能而言 Blade 基本上是零开销。Blade 视图文件使用 .blade.php 文件扩展并存放在 resources/views 目录下。 模板继承 定义布局 使用 Blade 的两个最大优点是模板继承和片段组合,开始之前让我们先看一个例子。首先,我们测试“主”页面布局,由于大多数 Web 应用在不同页面中使用同一个布局,可以很方便的将这个布局定义为一个单独的 Blade 页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 存放在 resources/views/layouts/app.blade.php --> <html> <head> <title>应用名称 - @yield('title')</title> </head> <body> @section('sidebar') 这里是侧边栏 @show <div class="container"> @yield('content') </div> </body> </html> |
正如你所看到的,该文件包含典型的 HTML 标记,不过,注意 @section 和 @yield 指令,前者正如其名字所暗示的,定义了一个内容片段,而后者用于显示给定片段的内容。 现在我们已经为应用定义了一个布局,接下来让我们定义继承该布局的子页面吧。 继承布局 定义子页面的时候,可以使用 Blade 的 @extends 指令来指定子页面所继承的布局,继承一个 Blade 布局的视图可以使用 @section 指令注入内容到布局定义的内容片段中,记住,如上面例子所示,这些片段的内容将会显示在布局中使用 @yield 的地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!-- 存放在 resources/views/child.blade.php --> @extends('layouts.app') @section('title', 'Laravel学院') @section('sidebar') @parent <p>Laravel学院致力于提供优质Laravel中文学习资源</p> @endsection @section('content') <p>这里是主体内容,完善中...</p> @endsection |
在本例中,sidebar 片段使用 @parent 指令来追加(而非覆盖)内容到继承布局的侧边栏,@parent 指令在视图渲染时将会被布局中的内容替换。 注:与之前的示例相反,sidebar 部分以 @endsection 结束而不是 @show,@endsection 指令只是定义一个 section 而 @show 指令定义并立即返回这个 section。 Blade 视图可以通过 view 方法直接从路由中返回:
1 2 3 4 |
Route::get('blade', function () { return view('child'); }); |
这样在浏览器中访问 http://blog.test/blade,就可以看到页面显示如下: 现在页面还很粗糙,没有任何样式,后面学习前端组件后可以回来完善。 组件 & 插槽 组件和插槽给内容片段(section)和布局(layout)带来了方便,不过,有些人可能会发现组件和插槽的模型更容易理解。首先,我们假设有一个可复用的“alert”组件,我们想要在整个应用中都可以复用它:
1 2 3 4 5 6 |
<!-- /resources/views/alert.blade.php --> <div class="alert alert-danger"> {{ $slot }} </div> |
{{ $slot }} 变量包含了我们想要注入组件的内容,现在,要构建这个组件,我们可以使用 Blade 指令 @component:
1 2 3 4 |
@component('alert') <strong>Whoops!</strong> Something went wrong! @endcomponent |
有时候为组件定义多个插槽很有用。下面我们来编辑alert组件以便可以注入“标题”,命名插槽可以通过“echoing”与它们的名字相匹配的变量来显示:
1 2 3 4 5 6 7 |
<!-- /resources/views/alert.blade.php --> <div class="alert alert-danger"> <div class="alert-title">{{ $title }}</div> {{ $slot }} </div> |
现在,我们可以使用指令 @slot 注入内容到命名的插槽。任何不在 @slot 指令中的内容都会被传递到组件的 $slot变量中:
1 2 3 4 5 6 7 8 |
@component('alert') @slot('title') Forbidden @endslot You are not allowed to access this resource! @endcomponent |
当我们在浏览器中查看这个组件内容的话,对应输出如下: 这段代码的意思是通过组件名 alert 去查找对应的视图文件,装载到当前视图,然后通过组件中 @slot 定义的插槽内容去渲染插槽视图中对应的插槽位,如果组件没有为某个插槽位定义对应的插槽内容片段,则组件中的其他不在 @slot 片段中的内容将会用于渲染该插槽位,如果没有其他多余内容则对应插槽位为空。 传递额外数据到组件 有时候你可能需要传递额外数据到组件,出于这个原因,你可以传递数组数据作为第二个参数到 @component 指令,所有数据都会在组件模板中以变量方式生效:
1 2 3 4 |
@component('alert', ['foo' => 'bar']) ... @endcomponent |
组件别名 如果 Blade 组件存储在子目录中,你可能想要给它们起别名以便访问。例如,假设有一个存放在 resources/views/components/alert.blade.php 的 Blade 组件,你可以使用 component 方法将这个组件设置别名为 alert(原名是 components.alert)。通常,这个操作在 AppServiceProvider 的 boot 方法中完成:
1 2 3 4 |
use Illuminate\Support\Facades\Blade; Blade::component('components.alert', 'alert'); |
组件设置别名后,就可以使用如下指令来渲染:
1 2 3 4 |
@alert(['type' => 'danger']) You are not allowed to access this resource! @endalert |
如果没有额外插槽的话也可以省略组件参数:
1 2 3 4 |
@alert You are not allowed to access this resource! @endalert |
数据显示 可以通过两个花括号包裹变量来显示传递到视图的数据,比如,如果给出如下路由:
1 2 3 4 |
Route::get('greeting', function () { return view('welcome', ['name' => '学院君']); }); |
那么可以通过如下方式显示 name 变量的内容:
1 2 |
你好, {{ $name }}。 |
当然,不限制显示到视图中的变量内容,你还可以输出任何 PHP 函数的结果,实际上,可以将任何 PHP […]
View Details基础组件 —— Session
简介 由于 HTTP 协议本身是无状态的,上一个请求与下一个请求无任何关联,为此我们引入 Session 来存储用户请求信息以解决特定场景下无状态导致的问题(比如登录、购物)。Laravel 通过简洁的 API 统一处理后端各种 Session 驱动,目前开箱支持的流行后端驱动包括 Memcached、Redis 和数据库。 学院君注:Laravel 并没有使用 PHP 内置的 Session 功能,而是自己实现了一套更加灵活更加强大的 Session 机制,核心逻辑请参考 Illuminate\Session\Middleware\StartSession 这个中间件,因此在 Laravel 应用中不要试图通过 $_SESSION 方式去获取应用的 Session 值,这是徒劳的。另外,还有一个大家都感到困惑的问题,就是在 Laravel 的控制器构造函数中是无法获取应用 Session 数据的,这是因为 Laravel 的 Session 通过 StartSession 中间件启动,既然是中间件就会在服务容器注册所有服务之后执行,而控制器们的构造函数都是在容器注册服务的时候执行的,所以这个时候 Session 尚未启动,有何来的获取数据呢?解决办法是将获取 Session 数据逻辑后置或者在构造函数中引入在 StartSession 之后执行的中间件。 配置 Session 配置文件位于 config/session.php。默认情况下,Laravel 使用的 Session 驱动为 file 驱动,这对许多应用而言是没有什么问题的。在生产环境中,你可能考虑使用 memcached 或者 redis 驱动以便获取更佳的 Session 性能,尤其是线上同一个应用部署到多台机器的时候,这是最佳实践。 Session 驱动用于定义请求的 Session 数据存放在哪里,Laravel 可以处理多种类型的驱动: file – Session 数据存储在 storage/framework/sessions 目录下; cookie – Session 数据存储在经过安全加密的 Cookie 中; database – Session 数据存储在数据库中 memcached / redis – Session 数据存储在 Memcached/Redis 缓存中,访问速度最快; array – Session 数据存储在简单 PHP 数组中,在多个请求之间是非持久化的。 注:数组驱动通常用于运行测试以避免 Session 数据持久化。 驱动预备知识 数据库 当使用 database 作为 Session 驱动时,需要设置表包含 Session 字段,下面是该数据表的表结构声明:
1 2 3 4 5 6 7 8 9 |
Schema::create('sessions', function ($table) { $table->string('id')->unique(); $table->unsignedInteger('user_id')->nullable(); $table->string('ip_address', 45)->nullable(); $table->text('user_agent')->nullable(); $table->text('payload'); $table->integer('last_activity'); }); |
你可以使用 Artisan 命令 session:table 在数据库中创建这张表:
1 2 3 |
php artisan session:table php artisan migrate |
Redis 在 Laravel 中使用 […]
View Details基础组件 —— 路由
路由入门 最基本的 Laravel 路由只接收一个 URI 和一个闭包,并以此为基础提供一个非常简单优雅的路由定义方法:
1 2 3 4 |
Route::get('hello', function () { return 'Hello, Welcome to LaravelAcademy.org'; }); |
我们以在安装配置文档中新建的 blog 应用为例,在 routes/web.php 中定义该路由:  在浏览器中通过 http://blog.test/hello (我使用 Valet 作为开发环境,故而对应域名是 blog.test,实际域名以自己配置的为准)即可访问我们刚刚定义的路由,页面输出内容如下:
1 2 |
Hello, welcome to LaravelAcademy.org |
默认路由文件 所有 Laravel 路由都定义在位于 routes 目录下的路由文件中,这些文件通过框架自动加载,相应逻辑位于 app/Providers/RouteServiceProvider 类。routes/web.php 文件定义了 Web 界面的路由,这些路由被分配到了 web 中间件组,从而可以使用 Session 和 CSRF 保护等功能。routes/api.php 中的路由是无状态的,这是因为被分配到了 api 中间件组。 对大多数应用而言,都是从 routes/web.php 文件开始定义路由。定义在 routes/web.php 中的路由可以通过在浏览器地址栏输入相应的 URL 进行访问,例如,你可以通过 http://blog.test/user 访问下面的路由:
1 2 |
Route::get('/user', 'UsersController@index'); |
正如前面所提到的,定义在 routes/api.php 文件中的路由通过 app/Providers/RouteServiceProvider 的处理被嵌套在一个路由群组中, 在这个群组中,所有路由会被自动添加 /api 前缀,所以你不需要再到路由文件中为每个路由手动添加,你可以通过编辑 RouteServiceProvider 类来修改路由前缀以及其他的路由群组选项:  有效的路由方法 我们可以注册路由来响应任何 HTTP 请求动作:
1 2 3 4 5 6 7 |
Route::get($uri, $callback); Route::post($uri, $callback); Route::put($uri, $callback); Route::patch($uri, $callback); Route::delete($uri, $callback); Route::options($uri, $callback); |
有时候还需要注册一个路由响应多种 HTTP 请求动作 —— 这可以通过 match 方法来实现。或者,可以使用 any 方法注册一个路由来响应所有 HTTP 请求动作:
1 2 3 4 5 6 7 8 |
Route::match(['get', 'post'], 'foo', function () { return 'This is a request from get or post'; }); Route::any('bar', function () { return 'This is a request from any HTTP verb'; }); |
测试 GET 请求的时候直接在浏览器中输入请求地址即可,测试 POST 请求可以通过客户端工具,比如 Advanced REST Client,该工具可以在 Chrome 应用商店下载到,此外如果上面的路由是定义在 routes/web.php 的话,在测试 POST 请求之前,需要将对应路由取消 CSRF 保护检查,否则会返回 419 状态码导致无法请求成功,取消的方法是在 app/Http/Middleware/VerifyCsrfToken 中设置排除检查路由:  下面我们来测试下 POST 请求:  如果路由是定义在 routes/api.php 的话,则无需关注 CSRF 保护问题,比如我们在 routes/api.php 定义 bar 路由,并且在 VerifyCsrfToken 的 $except 属性数组中移除 bar,然后我们测试下对 http://blog.test 的 POST 请求: 正如我们所预测的,完全没有任何问题,背后的原因是因为 web 路由文件中定义的路由都位于 web 中间件群组,该群组默认启用 CSRF 保护检查,而 api 路由文件位于 api 路由群组,该群组下的路由主要用于 第三方 API 请求,没办法进行 CSRF 检查,所以不需要做任何处理。 CSRF 保护 在 routes/web.php 路由文件中所有请求方式为 PUT、POST 或 DELETE 的路由对应的 HTML 表单都必须包含一个 CSRF 令牌字段,否则,请求会被拒绝。关于 […]
View DetailsLaravel 5.1 中路由绑定 Controller 包含子目录写法
StackOverFlow【已答复】:How to put controller inside folder in laravel 5.1.3? 【可以使用命令在项目根目录一键创建 php artisan make:controller 目录名/控制器名 --plain (是小写 php,CSDN…我服)】 【执行后可以省去 1-5 步】 首先在 /app/Http/Controllers 下新建目录,如 User User 内新建 PHP 控制器文件,如 UserController.php 此时命名空间应当是这样的: namespace App\Http\Controllers\User; 【!重点!】 namespace 下必需含有:use App\Http\Controllers\Controller; 类名没有什么好说的,class UserController extends Controller 写一个方法到控制器内,如:public function papapa(){return 'papapa'} 回到 /app/Http/routes.php 文件,绑定控制器:Route::get ( '/user', 'User\UserController@papapa' );搞定。 看了下 StackOverFlow,有一个说法是创建好目录,然后直接写不包含路径的路由,最后在项目目录执行 composer dump-autoload 即可。【测试无效】 对了,还可以用路由群组的形式绑定:
1 2 3 4 5 |
Route::group ( [ 'namespace' => 'User' ], function () { Route::get ( '/user/login', 'UserController@index' ); } ); |
from:https://blog.csdn.net/maxsky/article/details/54017981
View Detailssession fixation攻击
什么是session fixation攻击 Session fixation有人翻译成“Session完成攻击”[1],实际上fixation是确知和确定的意思,在此是指Web服务的会话ID是确知不变的,攻击者为受害着确定一个会话ID从而达到攻击的目的。在维基百科中专门有个词条Session fixation,在此引述其攻击情景,防范策略参考原文。 攻击情景 原文中Alice是受害者,她使用的一个银行网站http://unsafe/存在session fixation漏洞,Mallory是攻击者,他想盗窃Alice的银行中的存款,而Alice会点击Mallory发给她的网页连接(原因可能是Alice认识Mallory,或者她自己的安全意识不强)。 攻击情景1:最简单:服务器接收任何会话ID 过程如下: Mallory发现http://unsafe/接收任何会话ID,而且会话ID通过URL地址的查询参数携带到服务器,服务器不做检查 Mallory给Alice发送一个电子邮件,他可能假装是银行在宣传自己的新业务,例如,“我行推出了一项新服务,率先体验请点击:http://unsafe/?SID=I_WILL_KNOW_THE_SID",I_WILL_KNOW_THE_SID是Mallory选定的一个会话ID。 Alice被吸引了,点击了 http://unsafe/?SID=I_WILL_KNOW_THE_SID,像往常一样,输入了自己的帐号和口令从而登录到银行网站。 因为服务器的会话ID不改变,现在Mallory点击 http://unsafe/?SID=I_WILL_KNOW_THE_SID 后,他就拥有了Alice的身份。可以为所欲为了。 攻击情景2:服务器产生的会话ID不变 过程如下: Mallory访问 http://unsafe/ 并获得了一个会话ID(SID),例如服务器返回的形式是:Set-Cookie: SID=0D6441FEA4496C2 Mallory给Alice发了一个邮件:”我行推出了一项新服务,率先体验请点击:http://unsafe/?SID=0D6441FEA4496C2" Alice点击并登录了,后面发生的事与情景1相同 攻击情景3:跨站cookie(cross-site cooking) 利用浏览器的漏洞,即使 http://good 很安全,但是,由于浏览器管理cookie的漏洞,使恶意网站 http://evil/ 能够向浏览器发送 http://good 的cookie。过程如下: Mallory给Alice发送一个邮件“有个有趣的网站:http://evil 很好玩,不妨试试” Alice访问了这个链接,这个网站将一个会话ID取值为I_WILL_KNOW_THE_SID 的 http://good/ 域的cookie设置到浏览器中。 Mallory又给Alice发了个邮件:“我行推出了一项新服务,率先体验请点击:http://good/” 如果Alice登录了,Mallory就可以利用这个ID了 from:http://www.360doc.com/content/11/1028/16/1542811_159889635.shtml
View Details设置redis访问密码
在服务器上,这里以linux服务器为例,为redis配置密码。 1.第一种方式 (当前这种linux配置redis密码的方法是一种临时的,如果redis重启之后密码就会失效,) (1)首先进入redis,如果没有开启redis则需要先开启: [root@iZ94jzcra1hZ bin]# redis-cli -p 6379 127.0.0.1:6379> (2)查看当前redis有没有设置密码: 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "" (3)为以上显示说明没有密码,那么现在来设置密码: 127.0.0.1:6379> config set requirepass abcdefg OK 127.0.0.1:6379> (4)再次查看当前redis就提示需要密码: 127.0.0.1:6379> config get requirepass (error) NOAUTH Authentication required. 127.0.0.1:6379> 2.第二种方式 (永久方式) 需要永久配置密码的话就去redis.conf的配置文件中找到requirepass这个参数,如下配置: 修改redis.conf配置文件 # requirepass foobared requirepass 123 指定密码123 保存后重启redis就可以了 连接redis 1.redis-cli连接redis [root@iZ2ze3zda3caeyx6pn7c5zZ bin]# redis-cli 127.0.0.1:6379> keys * (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123 //指定密码 OK 127.0.0.1:6379> keys * 1) "a" 2) "cit" 3) "clist" 4) "1" 127.0.0.1:6379> 2.Jedis连接redis java 代码方式 //连接redis服务器,192.168.0.100:6379 jedis = […]
View Detailslaravel 如何引入自己的函数或类库
例如在app下建一个Common文件夹 在Common下建一个function.php 放入公共函数
1 2 3 4 |
例如: function test(){ echo 'this is a test'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
在项目目录下composer.json中加入 "autoload": { "files":[ "app/Common/function.php" ] } 在项目目录下执行 composer dump-autoload 在控制器的某个方法中调用 public function aa(){ test(); } |
from:https://blog.csdn.net/u010957293/article/details/52137241
View Details验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保
验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。 说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 异常详细信息: System.Web.HttpException: 验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。 分析: 分析后找到了问题的根源。首先,文章中提到,如果用GridView,并且指定了DataKeyNames属性,则出于安全的理由(因为DataKeyNames指定的字段代表数据的主键,且该主键值需要保存在视图状态中发送到客户端,用户如果篡改主键值,会导致安全问题),GridView会要求加密视图状态。为此会自动在页面表单</forms>之前添加一个
1 |
<input type="hidden" name="__VIEWSTATEENCRYPTED" id="__VIEWSTATEENCRYPTED" value="" /> |
。 然而,Atlas的UpdatePanel要求放置在<form></form>内部,也就是</form>之前。这就意味着添加的隐藏input控件没有被放置在UpdatePanel内,而是放置在UpdatePanel和</form>之间。 当UpdatePanel更新时,UpdatePanel内部的控件被提交到服务器进行处理(Patrial Rendering),而整个页面并没有被提交。也就是说隐藏的input控件没有随着一起提交。因此服务器并不知道提交的ViewState被加密了,从而导致MAC验证错误。 解决方法有二,仅供参考: 1.可以在当前页面的<page …>里加两个属性: enableEventValidation="false" viewStateEncryptionMode ="Never" 2.当然还可以在web.config里加入:(<system.web>之间)
1 |
<pages enableEventValidation="false" viewStateEncryptionMode ="Never" /> |
其余方法 在web.config中的pages节点上添加enableviewstatemac=false 附带: 一般而言是因为你的某些操作修改了视图状态,我猜测你可能使用了ajax并在客户端用javascript动态添加了某些项 1. 在出错页面的 <%@ page %>中加enableviewstatemac="false"无效。 2. 在web.config的 <system.web>节中加
1 |
<machineKey validationKey="3FF1E929BC0534950B0920A7B59FA698BD02DFE8" decryptionKey="280450BB36319B474C996B506A95AEDF9B51211B1D2B7A77" decryption="3DES" validation="SHA1"/> |
我的问题是加入:
1 |
<machineKey validationKey="d41d8cd98f00b204e9800998ecf8427e0e5798a7e2c46b2fd4f0277bceaf08e1" validation="SHA1"/> |
解决 最重要的是检查自己的页面,很可能是你的页面中的问题,多注意下,肯定能发现问题,而这个问题并没有报出你想要的错误 !!! 所以,不一定所有的解决方案都适合你!!! from:https://www.cnblogs.com/Setme/archive/2012/06/05/2537084.html
View Details