whitecube / laravel-cookie-consent
以符合欧盟标准的方式注册、配置并请求cookie同意。
Requires
- php: >=8.1
- laravel/framework: ^9|^10|^11
Requires (Dev)
- mockery/mockery: ^1.5
- orchestra/testbench: ^8.5|^9.0
- pestphp/pest: ^2.6
README
✅ 100% 遵守 GDPR
✅ 完全可定制
✅ 可与/无需 JavaScript 运行
根据 欧盟的 GDPR,对于您网站基本功能非必需的cookie,必须在使用之前获得您的最终用户明确同意其具体目的和收集个人数据。尽管一些非技术立法者决定了一些疯狂任意的要求,但总体来说 这是好事,因为它推动我们的行业走向更尊重和用户友好的方向发展。越来越多的非欧盟公民期望网站要求他们同意,这可能会包括您的目标受众。
面对现实,大多数时候您 可以 使用需要cookie使用的服务的替代品。最常见的情况是分析工具,例如 Google Analytics,可以很容易地被以下替代品替代:
- Fathom:由一些 Laravel 社区成员构建!
- Plausible:在欧盟制作和托管。
- Pirsch:在欧盟(德国)制作和托管。
- ... 想要在这个列表中添加一个有用的竞争对手? 提交一个问题!
使用这些替代品的主要优势是,您根本不需要请求明确同意,因为您不会使用任何非必需的cookie。这始终会提高您应用程序的可访问性和用户体验。
尽管如此,此包提供了您所需的所有工具,以覆盖适当的欧盟符合的cookie政策
- cookie 注册 & 配置
- Blade 视图和翻译文件,用于同意警报和弹出窗口
- Blade 指令和 Facade 方法,使您的生活更轻松
- JavaScript 代码,可增强前端用户体验
我们构建此包时考虑了灵活性:您将能够根据需要自定义内容、行为和样式。以下是它默认的样子
目录
安装
composer require whitecube/laravel-cookie-consent
此包将自动注册其服务提供程序。
使用
首先,发布包的文件
-
发布
CookiesServiceProvider
文件:php artisan vendor:publish --tag=laravel-cookie-consent-service-provider
-
在您的应用程序中注册服务提供程序。对于使用 Laravel 9 或 10 的应用程序,将服务提供程序添加到
config/app.php
中的providers
数组'providers' => ServiceProvider::defaultProviders()->merge([ // ... App\Providers\RouteServiceProvider::class, // IMPORTANT: add the following line AFTER "App\Providers\RouteServiceProvider::class," App\Providers\CookiesServiceProvider::class, ])->toArray(),
对于运行 Laravel 11 的应用程序,将服务提供程序添加到
bootstrap/providers.php
中的数组return [ App\Providers\AppServiceProvider::class, App\Providers\CookiesServiceProvider::class, ];
-
发布配置文件:
php artisan vendor:publish --tag=laravel-cookie-consent-config
如果您想自定义同意模态的视图
- 发布可自定义的视图:
php artisan vendor:publish --tag=laravel-cookie-consent-views
- 发布翻译文件:
php artisan vendor:publish --tag=laravel-cookie-consent-lang
有关自定义的更多信息请见下文。
现在,我们需要在刚刚发布的 App\Providers\CookiesServiceProvider::registerCookies()
方法中注册和配置使用的cookies。
namespace App\Providers; use Whitecube\LaravelCookieConsent\Consent; use Whitecube\LaravelCookieConsent\Facades\Cookies; use Whitecube\LaravelCookieConsent\CookiesServiceProvider as ServiceProvider; class CookiesServiceProvider extends ServiceProvider { /** * Define the cookies users should be aware of. */ protected function registerCookies(): void { // Register Laravel's base cookies under the "required" cookies section: Cookies::essentials() ->session() ->csrf(); // Register all Analytics cookies at once using one single shorthand method: Cookies::analytics() ->google( id: env('GOOGLE_ANALYTICS_ID') anonymizeIp: env('GOOGLE_ANALYTICS_ANONYMIZE_IP') ); // Register custom cookies under the pre-existing "optional" category: Cookies::optional() ->name('darkmode_enabled') ->description('This cookie helps us remember your preferences regarding the interface\'s brightness.') ->duration(120) ->accepted(fn(Consent $consent, MyDarkmode $darkmode) => $consent->cookie(value: $darkmode->getDefaultValue())); } }
有关可用的 cookie注册 方法的更多详情请见下文。
然后,让我们使用以下blade指令将同意脚本和模态框添加到应用程序的视图中:
@cookieconsentscripts
:用于添加包的默认JavaScript以及您需要的任何第三方脚本,以便获取最终用户的同意。@cookieconsentview
:用于渲染警告或弹出视图。
<!DOCTYPE html> <html lang="en"> <head> <!-- ... --> @cookieconsentscripts </head> <body> <!-- ... --> @cookieconsentview </body> </html>
注册cookie
此包旨在将cookie声明和文档集中到同一位置,以便保持项目的可维护性。然而,建议的方法不是强制性的。如果您希望在应用程序代码库的其它地方排队cookies或执行同意后的代码,请随意操作:我们有一些可用方法,在您需要检查请求生命周期中是否已授予同意时可能很有用。
选择cookie类别
所有已注册的cookies都附属于一个Cookie类别,这是一种方便地将cookies分组在相似主题下的方式。目标目的是通过提供易懂的摘要部分来增加详细信息的视图的可用性。
用户不是逐个同意每个cookie,而是同意这些类别。所有包含在同意类别中的cookies将自动被视为已明确同意。
本包包含3个基础类别
Cookies::essentials()
:列出所有为应用程序添加所需功能的cookies。此类别不能选择退出,并且自动包含包的同意cookie。Cookies::essentials()->session()
:注册Laravel的“session”cookie(在您的应用程序的session.cookie
配置中定义);Cookies::essentials()->csrf()
:注册Laravel的“XSRF-TOKEN” cookie。
Cookies::analytics()
:列出所有用于统计和数据收集的cookies。Cookies::analytics()->google(string $trackingId, bool $anonymizeIp)
:自动列出所有Google Analytics的cookies。 这还将自动注册Google Analytics的JS脚本,并在同意时将其注入到布局的<head>
中。很方便,对吧?
Cookies::optional()
:列出所有提供某种类型实用功能的cookies。由于此类别可以选择退出,因此相关功能应该在排队或依赖其cookies之前检查是否已授予同意。
您可以添加尽可能多的自定义类别。为此,只需在Cookies
外观上调用category(string $key, ?Closure $maker = null)
方法即可。
use Whitecube\LaravelCookieConsent\Facades\Cookies; $category = Cookies::category(key: 'my-custom-category');
可选的第二个参数,Closure $maker
,可用于定义自定义的CookiesCategory
实例。
use Whitecube\LaravelCookieConsent\Facades\Cookies; $category = Cookies::category(key: 'my-custom-category', maker: function(string $key) { return new MyCustomCategory($key); });
自定义类别类应该扩展Whitecube\LaravelCookieConsent\CookiesCategory
。
一旦定义,自定义类别可以通过它们的camelCase方法访问
use Whitecube\LaravelCookieConsent\Facades\Cookies; $category = Cookies::myCustomCategory();
为了向类别添加人类可读的标题和描述,您应该在cookieConsent::cookies.categories.[category-key]
翻译中插入新行。有关翻译的更多信息请见下文。
return [ // ... 'categories' => [ // ... 'my-custom-category' => [ 'title' => 'My custom category of cookies', 'description' => 'A short description of what these cookies are meant for.', ], // ... ], ];
cookie定义
一旦目标了一个类别,您就可以使用以下方法开始在其中定义cookies:
Cookies::essentials() // Targetting a category ->name('darkmode_enabled') // Defining a cookie ->description('Lorem ipsum') // Adding the cookie's description for display ->duration(120); // Adding the cookie's lifetime in minutes
使用这些方法,您必须通过每次调用一个类别来定义每个cookie。为了方便,也可以使用链式cookie(Closure|Cookie $cookie)
方法来链式定义cookie。
use Whitecube\LaravelCookieConsent\Cookie; Cookies::essentials() // Targetting a category ->cookie(function(Cookie $cookie) { $cookie->name('darkmode_enabled') // Defining a cookie ->description('Lorem ipsum') // Adding the cookie's description for display ->duration(120); // Adding the cookie's lifetime in minutes }) ->cookie(function(Cookie $cookie) { $cookie->name('high_contrast_enabled') // Defining a cookie ->description('Lorem ipsum') // Adding the cookie's description for display ->duration(60 * 24 * 365); // Adding the cookie's lifetime in minutes });
name(string $name)
必需。定义cookie名称。它用于显示,并在设置cookie时用作实际cookie的“键”。
description(string $description)
可选。为cookie添加文本描述。仅用于显示。
duration(int $minutes)
必需。定义cookie的寿命(分钟)。用于显示和设置cookie的实际过期日期。
accepted(Closure $callback)
可选的"accepted"回调在同意cookie所属类别的权限时被调用。这发生在用户配置cookie首选项之后,以及每次处理后续请求时。
回调至少接收一个参数,Consent $consent
,这是一个用于配置同意输出的对象。
script(string $tag)
:定义一个仅在同意后添加到布局的<head>
中的脚本标签;cookie(string $value, ?string $path = null, ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = null)
:定义一个在同意后添加到响应中的cookie。注意,它不再需要名称和持续时间,因为这些设置已经通过上述的name()
和duration()
方法定义。
use Whitecube\LaravelCookieConsent\Consent; $cookie->accepted(function(Consent $consent) { $consent->cookie(value: 'off')->script('<script src="' . asset('js/darkmode.js') . '"></script>'); });
其他参数可以类型提示,并由Laravel的服务容器解析
use App\Services\MyDependencyService; use Whitecube\LaravelCookieConsent\Consent; $cookie->accepted(function(Consent $consent, MyDependencyService $service) { $consent->script($service->getScriptTag()); });
自定义cookie属性
当构建自己的cookie通知设计时,您可能需要在Cookie
实例上使用额外的属性。我们已经为您做好了准备!
$cookie->color = 'warning'; echo $cookie->color; // "warning"
在幕后,这些魔法属性使用setAttribute
和getAttribute
方法
$cookie->setAttribute('icon', 'brightness'); echo $cookie->getAttribute('icon'); // "brightness"
但由于所有其他cookie定义方法都是链式调用的,您也可以将自定义属性作为链式方法调用
$cookie->subtitle('Darkmode preferences')->checkmark(true); echo $cookie->subtitle; // "brightness" echo $cookie->checkmark ? 'on' : 'off'; // "on"
检查同意
有几种方法可以检查显式的用户同意,每种方法在不同的上下文中都很有用。
使用Cookies
外观
安装此包时自动发现Cookies
外观。
use Whitecube\LaravelCookieConsent\Facades\Cookies; if(Cookies::hasConsentFor('my_cookie_name')) { // ... }
使用依赖注入
当与Laravel服务容器解析的方法一起使用时很有用。
use Whitecube\LaravelCookieConsent\CookiesManager; class FooController { public function __invoke(CookiesManager $cookies) { if($cookies->hasConsentFor('my_cookie_name')) { // ... } } }
定制
cookie通知很无聊,而这个包的默认设计也不例外。它已经被构建得非常健壮、易于访问和中立,因此可以在尽可能多的情况下使用。
然而,这个世界不应该是一个无聊的地方,即使cookie通知是项目法律要求的组成部分,为什么不让它成为给您的观众带来微笑的机会呢?cookie模态现在集成在每一个数字平台的用户体验中,因此它们应该相应地融合:这就是我们构建此包时考虑到完全灵活性的原因。
视图
一个好的起点是查看这个包的默认标记。如果您尚未发布,您可以通过使用php artisan vendor:publish --tag=laravel-cookie-consent-views
来访问视图,这将把我们的blade文件复制到您的应用程序的resources/views/vendor/cookie-consent
目录中。
在这里,您可以发挥无限的创意,并突破传统cookie通知或弹出窗口的界限。
渲染时,视图可以访问以下变量
$policy
:当定义时,指向您应用程序cookie政策页面的URL。为此,请参阅包的cookieconsent.php
配置文件。$cookies
:已注册的cookie类别及其附加的cookie定义。
为了添加按钮,我们建议使用包的@cookieconsentbutton()
blade指令
@cookieconsentbutton('accept.all')
:渲染一个按钮,目标指向此包的"同意所有cookie"API路由;@cookieconsentbutton('accept.essentials')
:渲染一个按钮,目标指向此包的"仅同意基本cookie"API路由;@cookieconsentbutton('accept.configuration')
:渲染一个按钮,目标指向此包的"同意自定义cookie选择"API路由。请注意,此路由需要请求负载中的所选cookie类别;@cookieconsentbutton('reset')
:渲染一个按钮,目标指向此包的"重置cookie配置"API路由。
样式
你可能已经注意到了,我们直接在cookies.blade.php
视图中使用了<style>
标签将设计中的CSS包含在内。如有需要,你可以移动、删除或替换它。事实上,我们建议使用正确的CSS文件,通过布局的<head>
中的<link>
标签或添加Tailwind类到HTML标记中添加自己的样式。
我们的CSS是从包含在此包的resources/scss
目录中的SASS文件编译而来的。如果你觉得这适合你的工作流程,请随意将其作为你自己的实现的起点。
JavaScript
请记住,cookie通知应在禁用JavaScript的情况下工作。此包的基本设计仅使用JavaScript作为额外的用户体验平滑层,但其功能并不依赖于它。
由于大多数实现都有相同的需求,我们将我们的JavaScript代码分为两部分
- 一个可重用的JavaScript库:通过
@cookieconsentscripts
blade指令自动加载,用于执行所有现有API路由的AJAX请求(使用Axios)LaravelCookieConsent.acceptAll()
LaravelCookieConsent.acceptEssentials()
LaravelCookieConsent.configure(data)
LaravelCookieConsent.reset()
- 一个实现上述库的脚本。就像我们的基本样式标签一样,此脚本直接通过
<script>
标签包含在cookies.blade.php
视图中。请随意删除它并添加你自己的交互逻辑。
文本内容和翻译
大部分显示的字符串都定义在cookieConsent::cookies
翻译文件中。此包附带了一些支持的地区,但如果你还没有包括在内,我们将非常感激一个PR。
如果没有发布,你可以使用php artisan vendor:publish --tag=laravel-cookie-consent-lang
编辑或填写翻译文件,这将把我们的翻译文件复制到你的应用vendor/cookieConsent
"lang"路径。
一些有用的提示
免责声明:我们不是律师。请始终咨询你的法律合作伙伴,了解哪些规则可能适用于你的项目。
cookie政策详细信息页面
你的网站需要一个专门的“Cookie政策”页面,其中包含有关cookie的详细信息,包括如何使用它们以及为什么使用它们等。这些页面还详细说明了包含哪些cookie。为了保持这些页面自动更新,请注意,此包可以使用Whitecube\LaravelCookieConsent\Facades\Cookies
外观在任何地方在你的应用程序中使用
<h1>Cookie Policy</h1> <p>...</p> <h2>How do we use cookies?</h2> @foreach(Cookies::getCategories() as $category) <table> <caption>{{ $category->title }}</caption> <thead> <tr> <th>Cookie</th> <th>Description</th> <th>Duration</th> </tr> </thead> <tbody> @foreach($category->getCookies() as $cookie) <tr> <td>{{ $cookie->name }}</td> <td>{{ $cookie->description }}</td> <td>{{ \Carbon\CarbonInterval::minutes($cookie->duration)->cascade() }}</td> </tr> @endforeach </tbody> </table> @endforeach <p>...</p>
关于Carbon\CarbonInterval
的cascade
方法的一个附带说明:当处理年份时,可能会出现一些意外的结果。默认情况下,CarbonInterval
的"年"因子将返回336天而不是365天。你可以通过定义自己的因子来更改此(例如在App\Providers\AppServiceProvider
中)
$factors = \Carbon\CarbonInterval::getCascadeFactors(); $factors['years'] = [365, 'dayz']; \Carbon\CarbonInterval::setCascadeFactors($factors);
关于CarbonInterval的更多陷阱信息,请参阅Constantin在Cahsingcode.dev的博客文章。
让您的用户改变主意
用户应能够随时更改他们的同意设置。不用担心,使用此包实现起来相当简单:生成一个按钮,将重置用户的cookie并再次显示同意模态框。
@cookieconsentbutton('reset')
这将输出一个完整的同意重置按钮。如果你希望对其进行自定义,你可以传递以下参数
@cookieconsentbutton(action: 'reset', label: 'Manage cookies', attributes: ['id' => 'reset-button', 'class' => 'btn'])
或者,为了更多的自定义,你可以更改位于resources/views/vendor/cookie-consent/button.blade.php
的模板(你将首先需要发布包的视图)。请注意,此模板用于此包中所有按钮组件,包括“接受所有”、“接受基本”和“保存配置”按钮。
如果你想知道为什么这些按钮被包裹在form
元素中:这样它们将在禁用JavaScript时工作,同时防止浏览器链接预取。
存储多个子域的用户偏好
默认情况下,此包将存储当前域的用户偏好。如果你希望在多个子域之间仅提示一次并保持用户的选择,你必须配置cookieconsent.cookie.domain
设置(位于config/cookieconsent.php
),如下所示
'cookie' => [ // ... 'domain' => '.mydomain.com', // notice the leading "." ],
将cookie注入到法律页面中
为了在法律页面(如服务条款或隐私政策页面)中提供详细的Cookie信息,您可以通过插入一个格式化的表格来列出Cookie名称、描述和持续时间。
这可以通过使用@cookieconsentinfo
Blade指令来实现,或者您可以直接在所见即所得(WYSIWYG)编辑器中放置该指令,稍后使用以下方法进行替换
{!! Cookies::replaceInfoTag($wysiwyg) !!}
这将自动生成并插入所需的Cookie信息,确保您的法律文件保持最新且符合要求。
保持可访问性
在定义您自己的视图和样式时,请记住,Cookie通知是应用程序整体可访问性的障碍。此外,它们应该在JavaScript未启用的情况下也能工作,这就是为什么这个包主要使用API路由和AJAX调用来增强用户体验。
开发路线图
我们有一些想法来进一步改进这个包。如果您希望添加有用功能,请随时在这个仓库上提交PR或问题。
- 在Cookies定义实例上添加一个
reset
回调来处理同意撤回; - 添加blade条件以简化同意和功能可用性的检查。
🔥赞助
如果您在生产应用程序中依赖这个包,请考虑赞助我们!这是帮助我们继续做我们热爱的事情——创建优秀的开源软件的最佳方式。
贡献
请随时提出更改建议、请求新功能或自行修复错误。我们相信还有许多可以改进的地方,我们非常乐意合并有用的PR。谢谢!
用❤️为开源制作
在Whitecube,我们每天的工作中大量使用开源软件。所以当我们有机会回馈社会时,我们非常兴奋!