首页
统计
壁纸
追番记录
优秀博主
关于
推荐
导航
工具
音乐解锁
Search
1
NAS的简单介绍
734 阅读
2
网站环境一键部署工具推荐
505 阅读
3
tp5-模型数据处理
405 阅读
4
win10镜像
359 阅读
5
第20200225期-电脑壁纸-P10
350 阅读
PHP
闲谈杂料
硬件系统
美图
ThinkPHP
笔记
数据库
Lua
登录
Search
标签搜索
ThinkPHP
MySQL
Laravel
PHP
API
GIT
Windows10
markdown
Web
跨域
ajax
小程序
壁纸
Linux
jsonp
try
异常
Dcat
UEFI
win10
phpfunny
累计撰写
104
篇文章
累计收到
24
条评论
首页
栏目
PHP
闲谈杂料
硬件系统
美图
ThinkPHP
笔记
数据库
Lua
页面
统计
壁纸
追番记录
优秀博主
关于
推荐
导航
工具
音乐解锁
搜索到
104
篇与
的结果
2025-04-02
【Lua基础】作用域
作用域区别在 Lua 中,function 和 local function 的主要区别在于它们的作用域(scope):function 声明:创建一个全局函数可以在声明之前被调用(函数提升)在整个程序中都可以访问会被添加到全局环境表中(通常是 _G 表)local function 声明:创建一个局部函数只能在声明之后被调用(没有函数提升)只在声明它的作用域内可见(比如在文件内或特定代码块内)不会污染全局命名空间访问速度更快(因为不需要在全局表中查找)内存效率更高(当离开作用域后可以被垃圾回收)建议:除非特别需要在其他模块中使用该函数,否则优先使用 local function使用 local function 可以避免命名冲突使用 local function 可以让代码更容易维护和理解,因为函数的作用域更明确作用域规则Lua 的作用域规则相对简洁,但灵活性强:默认全局变量 :未用 local 声明的变量默认是全局的。局部变量 :用 local 声明的变量仅在当前块(如函数、循环、代码块)内有效。作用域链 :内层作用域可以访问外层作用域的变量(遵循词法作用域规则)。local outer = 10 -- 外层局部变量 function test() local inner = 20 -- 函数内的局部变量 print(outer) -- 可以访问外层变量(输出 10) end test() print(inner) -- 错误:inner 在此作用域不可见 高级技巧1. 显式块级作用域(do...end)通过 do...end 创建临时作用域, 限制局部变量的生命周期 :do local temp = "临时变量" print(temp) -- 输出 "临时变量" end -- print(temp) 此处访问会报错(temp 已超出作用域) 用途 :避免变量污染全局命名空间。控制资源释放(如文件句柄)。2. 闭包与 UpvalueLua 的闭包(Closure)可以 捕获外层函数的局部变量 (称为 upvalue ),并保持其状态function counter() local count = 0 return function() -- 返回闭包函数 count = count + 1 return count end end local c1 = counter() print(c1()) -- 输出 1 print(c1()) -- 输出 2(闭包保留了 count 的状态) 特性 :Upvalue 的生命周期与闭包绑定,即使外层函数已返回。多个闭包共享同一个 Upvalue 时,修改会互相影响。3. 环境控制(_ENV 与 setfenv)Lua 通过 环境(Environment) 控制全局变量的访问,可用于沙盒隔离或模块化开发。(1) 修改函数环境-- 创建一个纯净的环境(无全局变量) local clean_env = { print = print } -- 只允许访问 print local code = [[ a = 10 -- 不会污染全局环境 print(a) -- 输出 nil(因为 clean_env 中无 a) ]] local func = load(code, "sandbox", "t", clean_env) func() (2) 使用 _ENV 元表通过元表实现环境继承:local shared_env = { x = 100 } setmetatable(shared_env, { __index = _G }) -- 继承全局环境 local code = [[ print(x) -- 输出 100(来自 shared_env) print(math.pi) -- 输出 3.1415(继承自 _G) ]] load(code, "env_test", "t", shared_env)() 4. 模块模式利用闭包和表返回实现模块封装:local mymodule = (function() local private = "私有数据" local function get() return private end local function set(value) private = value end return { get = get, set = set } -- 暴露接口 end)() print(mymodule.get()) -- 输出 "私有数据" mymodule.set("新值") print(mymodule.get()) -- 输出 "新值" 优点 :隐藏内部实现细节。避免全局命名冲突5. 动态作用域模拟Lua 默认是词法作用域,但可通过 debug 库模拟动态作用域(慎用):function dynamic_scope() local var = "动态值" local function inner() print(debug.getlocal(2, 1)) -- 获取调用者的局部变量 end inner() end dynamic_scope() -- 输出 nil(需要特定上下文) 建议:优先使用局部变量 :减少全局污染,提升性能(局部变量访问更快)。合理使用闭包 :注意内存泄漏风险(长期持有的闭包可能阻止 Upvalue 释放)。模块化设计 :通过环境控制或闭包封装功能。避免滥用动态作用域 :保持代码可预测性。
2025年04月02日
11 阅读
0 评论
0 点赞
2025-03-13
【LUA基础】全局表和局部表的应用
参考:dev/script/ssr/ssrgame/ui/zhuangshengUI.lua@P3 setmetatable+local 局部+等 组合在实际脚本开发的应用全局表zhuanshengUI = {} zhuanshengUI._hideMain = true local uinodes = setmetatable({}, { __index = function(t, key) rawset(t, key, {}) return t[key] end }) local ui = uinodes.ui这是一个常用的UI操作模式:uinodes是一个全局表,用于储存所有UI相关的节点引用uinodes.ui通常包含了通过GUI编辑器创建的所有UI组件引用实例:-- 获取UI引用 local ui = uinodes.ui -- 访问具体的UI组件 ui.Panel_1 -- 访问名为 Panel_1 的面板 ui.btn_close -- 访问关闭按钮 ui.img_bg -- 访问背景图片 ui.txt_title -- 访问标题文本 -- 对UI组件进行操作 GUI:setVisible(ui.Panel_1, true) -- 显示面板 GUI:setString(ui.txt_title, "新标题") -- 设置文本 GUI:setPosition(ui.img_bg, 100, 100) -- 设置位置主要用途:提供一个统一的方式访问UI组件避免重复获取UI组件引用使代码更清晰和易于维护通常在UI初始化时会设置这些引用function mianfeifuliUI.Init() -- 创建UI时自动保存所有组件引用到 uinodes.ui uinodes.ui = { Panel_1 = panel1, btn_close = closeBtn, img_bg = bgImage, -- ... 其他UI组件 } end这样在后续的代码中就可以通过 local ui = uinodes.ui 方便地访问所有UI组件。局部表local uinodes = setmetatable({}, { __index = function(t, key) rawset(t, key, {}) return t[key] end })这是创建一个特殊的表结构:local uinodes表示这是一个局部表,不是全局表只在当前文件(zhuanshengUI.lua)中可以访问其他文件无法直接访问这个 uinodessetmetatable是 Lua 的元表机制:第一个参数{} 是创建一个空表第二个参数是元表,定义了表的特殊行为__index是元表的一个元方法:当访问 uinodes 中不存在的键时会触发这个函数例如:当访问uinodes.ui 但 ui 不存在时这个设计的作用是:-- 当第一次访问 uinodes.ui 时 local ui = uinodes.ui -- 会自动创建一个新的空表并赋值给 uinodes.ui -- 相当于自动执行了: if not uinodes.ui then uinodes.ui = {} end使用实例:-- 第一次访问时自动创建空表 uinodes.ui.button1 = someButton -- uinodes.ui 会被自动创建 uinodes.windows.main = someWindow -- uinodes.windows 会被自动创建 -- 不需要事先声明: -- uinodes.ui = {} -- uinodes.windows = {}这种设计的好处:自动初始化:不需要手动创建子表防止错误:访问不存在的键时不会报错代码更简洁:减少了初始化代码按需创建:只有被访问的键才会创建对应的表
2025年03月13日
3 阅读
0 评论
0 点赞
2024-11-13
关于Larave中.env读取偶发性失效问题
相关问题.env设置了自定义参数,但env()函数读取失败只获取默认值编辑.env没有生效其他env问题问题描述在配置完.env后(增加了一些自定义KEY) 在程序中使用env()助手函数没有获取的键值。在Larave文档相关操作说明(config):需要删除env缓存文件并重新生成。执行发现依然没有生效。可是检查.env文件参数是没问题的,了解env()和config()区别后更是不解,明明用的env()的助手行数直接获取env文件中的参数,和缓存没有关系,但实际发现确实读取不到,获取的是env()参数二设置的默认值。最终也很疑惑希望知情之人能告知一二。解决过程检查.env配置文件中设置正确的参数SERVICE_IP="42.XXX.XXX.163" TENCENTCLOUD_SECRET_ID=AKIDgXXXXXXXXXXXXXXXXXXXXXXXXMtENL4 TENCENTCLOUD_SECRET_KEY=cwDPciXXXXXXXXXXXXXXXVYXLwKVWM TENCENTCLOUD_CAPTCHA_APPID=1900000000 TENCENTCLOUD_APPSECRET_KEY=hi8XXXXXXXXXXXXXXXX6tqbU WECHAT_APP_ID=wx000000000000ce WECHAT_APP_SECRET=80cXXXXXXXXXXXXXXfb18 WECHAT_TOKEN=76976000000000000000acb834a WECHAT_ENCODING_AES_KEY=u7u2B00000000000000001jZrv9设置config配置参数/config/services.phpreturn [ ... 'easywechat' => [ 'official_account' => [ 'app_id' => env('WECHAT_APP_ID', ''), 'secret' => env('WECHAT_APP_SECRET', ''), 'token' => env('WECHAT_TOKEN', ''), 'aes_key' => env('WECHAT_ENCODING_AES_KEY', '') ], ], 'tencentcloud' => [ 'secret_id' => env('TENCENTCLOUD_SECRET_ID', ''), 'secret_key' => env('TENCENTCLOUD_SECRET_KEY', ''), 'captcha_appid' => env('TENCENTCLOUD_CAPTCHA_APPID', ''), 'appsecret_key' => env('TENCENTCLOUD_APPSECRET_KEY', '') ], 'service_ip' => env('SERVICE_IP', '') ];删除config缓存并重新生成#清除config缓存文件 php artisan config:clear #生成config缓存文件 php artisan config:cache测试请在需要获取参数的地方使用config()助手函数dd(config('services.tencentcloud.captcha.appid')); dd(config('services.service_ip'));最优雅的方式env()方法不要在业务代码中使用,只在配置文件中使用。拓展一,最优雅获取配置方式上述"解决过程"为最佳方式二,助手函数中env()和config()区别助手函数用途用法示例env()函数用于直接从 .env 文件中读取环境变量。它主要用于在配置文件中读取环境变量,以便在不同的环境中使用不同的配置值。env('API_KEY', 'default_value');在.env文件中写法 API_KEY=your_api_keyconfig()用于从配置文件中读取配置值。配置文件位于 config 目录下,每个文件对应一个特定的配置领域。config('app.api_key');在/config/app.php写法 return ['api_key' => env('API_KEY', 'default_key')];两者区别读取来源不同:env() 从 .env 文件中读取环境变量。config() 从 config 目录下的配置文件中读取配置值。使用场景不同:env() 通常用于在配置文件中读取环境变量,以便在不同的环境中使用不同的配置值。config() 用于在代码中读取配置文件中的配置值。缓存机制不同:env() 不会被缓存,每次调用都会从 .env 文件中读取。config() 会被缓存,使用 php artisan config:cache 命令生成的缓存文件 bootstrap/cache/config.php 中读取配置值,提高性能。三,关于env()获取为空原因
2024年11月13日
8 阅读
0 评论
0 点赞
2024-09-06
【Lua基础】元表与元方法
元表(metatable)lua中元表是用来存储元方法的表。我个人理解类似php中集合的概念但功能更多。元表拥有强大的特性:控制索引和赋值行为,控制算术运算,控制比较操作,控制调用行为,控制长度操作,控制转换行为,控制迭代行为,控制元表的更改。控制索引和赋值行为__index: 当尝试访问一个表中不存在的键时,Lua 会检查该表的元表是否定义了 __index 属性。如果定义了,则Lua会尝试根据这个属性提供的值来查找键。__newindex: 当尝试设置一个表中不存在的键时,Lua 会检查该表的元表是否定义了 __newindex 属性。如果定义了,则Lua会根据这个属性提供的值来处理这个赋值操作。控制算术运算__add, __sub, __mul, __div, __mod, __unm: 这些元方法允许你定义表和其他对象之间的算术运算行为。控制比较操作__eq, __lt, __le: 这些元方法允许你定义表之间的比较行为。控制调用行为__call: 允许你将表当作函数来调用。控制长度操作__len: 允许你定义表的长度(# 操作符)。控制转换行为__tostring, __concat: 这些元方法允许你在将表转换为字符串或与其他字符串拼接时定义行为。控制迭代行为__mode: 在Lua 5.2及更高版本中,此元方法允许你指定哪些字段应该使用next函数迭代时可见。控制元表的更改__metatable: 如果这个元方法存在,那么尝试更改一个表的元表时会调用这个方法。设置元表演示-- mytable = {} -- 普通表 mymetatable = {} -- 元表 setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表 --简写 mytable = setmetatable({},{})如果元表中有相同元数据,则可以进行加减操作演示两个表相加操作-- 自定义计算表中最大键值函数 table_maxn,即返回表最大键值 function table_maxn(t) local mn = 0 for k, _ in pairs(t) do if type(k) == "number" and k > mn then mn = k end end return mn end -- 两表相加操作 mytable = setmetatable({ 1, 2, 3 }, { __add = function(mytable, newtable) local max_key_mytable = table_maxn(mytable) for i = 1, table_maxn(newtable) do table.insert(mytable, max_key_mytable + i, newtable[i]) end return mytable end }) secondtable = {4, 5, 6} mytable = mytable + secondtable for k, v in ipairs(mytable) do print(k, v) end --输出结果 1 1 2 2 3 3 4 4 5 5 6 6其他:拓展展示使用元表来拓展表的功能-- 创建一个表 local myTable = { name = "example", value = 42 } -- 创建一个元表 local myMeta = { __index = { description = "This is an example table." }, __tostring = function(t) return string.format("Name: %s, Value: %d", t.name, t.value) end, __call = function(t, arg1, arg2) print("Called with:", arg1, arg2) end } -- 给myTable设置元表 setmetatable(myTable, myMeta) -- 访问不存在的键 print(myTable.description) -- 输出: This is an example table. -- 打印表 print(tostring(myTable)) -- 输出: Name: example, Value: 42 -- 调用表 myTable("Hello", "World") -- 输出: Called with: Hello World在这个例子中,我们定义了一个元表 myMeta,它包含了几个元方法来改变 myTable 的行为。通过设置 myTable 的元表为 myMeta,我们可以扩展 myTable 的功能,如定义其描述、改变其字符串表示形式,以及使其可调用。元表使得Lua中的表可以非常灵活,并且可以用来模拟面向对象编程中的类和继承的概念。通过适当的元表设计,你可以创建非常强大的数据结构和模式。在Lua中,__index 和 __newindex 是元表(metatable)中的两个特殊方法,用于实现表的继承和动态扩展功能。当一个表作为另一个表的元表时,这两个方法就变得非常重要。__index元方法__index是一个索引器,当尝试访问一个表中不存在的键时,Lua会检查该表的元表是否定义了__index属性。如果定义了,则Lua会尝试根据这个属性提供的值来查找键。如果 __index 是一个表,Lua会在那个表中查找键。如果 __index 是一个函数,Lua会调用该函数,并将表以及键作为参数传递给这个函数。示例local parent = { a = 1, b = 2 } local child = {} -- 设置parent为child的元表 setmetatable(child, { __index = parent }) print(child.a) -- 输出: 1 print(child.b) -- 输出: 2Lua 查找一个表元素时的规则:在表中查找,如果找到,返回该元素,找不到则继续判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。判断元表有没有__index方法,如果__index方法为nil,则返回nil; 如果__index方法是一个表,则重复1、2、3; 如果__index方法是一个函数,则返回该函数的返回值。__newindex元方法__newindex与__index类似,但它是在尝试设置一个表中不存在的键时触发。如果设置了__newindex,Lua会根据它的值决定如何处理这个赋值操作。如果 __newindex是一个表,Lua会尝试在那个表中设置键的值。如果 __newindex是一个函数,Lua会调用该函数,并将表、键和要设置的值作为参数传递给这个函数。示例:假设我们想要记录每次对 child 表进行赋值的操作local parent = { a = 1, b = 2 } local meta = { __newindex = function(t, key, value) print("Setting " .. key .. " to " .. value) t[key] = value end } setmetatable(parent, meta) parent.c = 3 -- 输出: Setting c to 3 print(parent.c) -- 输出: 3 --在这个例子中,当我们尝试给parent表添加一个新的键c时, --__newindex定义的函数被调用,并且打印出一条消息,同时仍然允许赋值操作。总结:__index 用于处理读取不存在的键时的行为。__newindex 用于处理写入不存在的键时的行为。
2024年09月06日
7 阅读
0 评论
0 点赞
2024-07-12
Dcat处理tinymce图片上传
tinymce 插件内置在dcatadmin中。tinymce图片上传默认路径和dcatadmin图片上传保存路径不一致。 需要更改tinymce上传配置app/Admin/bootstrap.php 文件处修改 Editor 组件样式use Dcat\Admin\Form\Field\Editor; Editor::resolving(function (Editor $editor) { $editor->options([ 'plugins' => [ 'advlist', 'autolink', 'link', 'image', 'media', 'lists', 'preview', 'code', 'help', 'fullscreen', 'table', 'autoresize', 'codesample', 'batchUploadImage', ], 'toolbar' => [ 'undo redo | preview fullscreen | styleselect | fontsizeselect bold italic underline strikethrough forecolor backcolor | link image batchUploadImage media blockquote removeformat codesample', 'alignleft aligncenter alignright alignjustify| indent outdent bullist numlist table subscript superscript | code', ], 'min_height' => 400, 'save_enablewhendirty' => true, 'convert_urls' => false, ]); });
2024年07月12日
8 阅读
0 评论
0 点赞
2024-05-17
使用Laravel事件系统
比如在用户注册时候需要一些额外的操作。 使用laravel中的事件系统去创建事件和监控器去实现便于开发和维护。文档介绍 https://learnku.com/docs/laravel/8.x/events/9391#01e998创建事件和监控器#指令创建事件 php artisan make:event UserRegistered #指令创建监控器 php artisan make:listener CreateUserDatabase --event=UserRegistered事件案例代码:<?php namespace App\Events; class UserRegistered { /** * Create a new event instance. * * @return void */ public function __construct(public int $userId) { //Log::debug('UserRegistered注册事件'); } } 监控案例代码:<?php namespace App\Listeners; use App\Events\UserRegistered; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; class CreateUserDatabase implements ShouldQueue { /** * 任务将被发送到的队列的名称 * * @var string|null */ public $queue = 'listeners'; /** * Create the event listener. * * @return void */ // public function __construct(){} /** * Handle the event. * * @param \App\Events\UserRegistered $event * @return void */ public function handle(UserRegistered $event) { Log::debug('触发了用户注册事件 USER_ID: ' . $event->userId); DB::table('users')->where('id', $event->userId)->update(['deleted_at' => time()]); try { DB::beginTransaction(); #创建新用户专属数据库 // DB::select('select * from users where active = ?', [1]); #执行sql原生操作 #创建上报字段信息表 DB::commit(); } catch (\Exception $e) { DB::rollBack(); } } /** * 获取监听器队列的名称 * * @return string */ // public function viaQueue() // { // return $this->queue; // } }配置事件与监听器的绑定打开 app/Providers/EventServiceProvider.php 文件。protected $listen = [ UserRegistered::class => [ CreateUserDatabase::class, ], ];使用事件在想要触发的位置去进行触发事件的监听use App\Events\UserRegistered; //注册 public function register(Request $request) { $input = $request->only('account_name', 'password'); event(new UserRegistered(2)); #2为传递的用户ID return $this->services->register($input); }事件执行方式事件执行有两种方式方式一,同步触发(同步执行)这是最直接的触发方式,事件在触发后,相应的监听器会立即执行,执行过程与触发事件的代码在同一请求生命周期内完成。同步触发适用于那些执行速度较快、不影响用户体验的操作。同步触发事件的典型代码示例如下:use App\Events\SomeEvent; // 触发事件 event(new SomeEvent($data));方式二,异步触发(队列方式)对于耗时较长的事件处理逻辑,如发送邮件、短信通知、复杂的数据处理等,推荐使用异步触发方式,以避免阻塞用户的请求响应。Laravel 提供了队列(Queue)系统来实现异步处理。异步触发事件通常有两种模式:使用 Queueable 特性在事件类中使用 Illuminate\Queue\InteractsWithQueue 特性,并实现 shouldQueue 方法,使事件变为可队列化的。然后,当触发该事件时,Laravel 会自动将其推送到队列中异步处理。use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class SomeEvent implements ShouldQueue { use Dispatchable, InteractsWithQueue; // ...构造函数和属性... public function handle() { // 事件处理逻辑 } }在监听器中使用队列即使事件本身没有实现 ShouldQueue 接口,也可以在监听器的 handle 方法中将耗时操作放入队列。这要求监听器实现 ShouldQueue 接口,并配置监听器为异步处理。use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class SomeEventListener implements ShouldQueue { use InteractsWithQueue; public function handle(SomeEvent $event) { // 将耗时操作放入队列处理 SomeLongRunningJob::dispatch($event->data); } }触发队列任务在上述异步处理方式中,提到的 SomeLongRunningJob 是一个队列任务的例子。你可以使用 Laravel 的任务调度器(Jobs)配合队列来进一步处理复杂的异步逻辑。创建队列任务并将其加入队列的代码示例如下:use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\Jobs\Job; use Illuminate\Contracts\Queue\ShouldQueue; class SomeLongRunningJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, SerializesModels; public $data; public function __construct($data) { $this->data = $data; } public function handle() { // 执行耗时任务 } } // 触发队列任务 SomeLongRunningJob::dispatch($data);总结Laravel 提供了灵活的事件触发机制,无论是同步还是异步处理,都能通过简洁的API实现复杂逻辑的解耦和高效执行。
2024年05月17日
9 阅读
0 评论
0 点赞
2023-12-06
MySQL备份指令
1、mysql备份单个数据库命令mysqldump --column-statistics=0 -h主机ip -P端口号 -u数据库用户名 -p数据库密码 数据库名称 > 想要备份的文件名称.sql2、直接将MySQL数据库压缩备份mysqldump -h主机ip -u数据库用户名 -p数据库密码 数据库名称| gzip > 想要备份的文件名称.sql.gz3、备份MySQL数据库某个(些)表mysqldump -h主机ip -u数据库用户名 -p数据库密码 数据库名称 表1 表2 > 想要备份的文件名称.sql4、同时备份多个MySQL数据库mysqldump -h主机ip -u数据库用户名 -p数据库密码 数据库1 数据库2 数据库3 > 想要备份的文件名称.sql5、仅备份数据库结构mysqldump –no-data 数据库1 数据库2 数据库3 > 想要备份的文件名称.sql6、备份服务器上所有数据库mysqldump –all-databases > 想要备份的文件名称.sql7、还原MySQL数据库的命令mysql -h主机ip -u数据库用户名 -p数据库密码 数据库名称 < 备份文件.sql8、还原压缩的MySQL数据库gunzip < 备份文件.sql.gz | mysql -u用户 -p密码 数据库名称9、将数据库转移到新服务器mysqldump -u用户 -p密码 数据库名称 | mysql –host=127.0.0.1 -C 数据库名称其他一些报错【unknown option ‘-b’ 错误】解决方式: 将 -database 改为 --database【Unknown table ‘column_statistics’ in information_schema 错误】错误原因: 因为新版的mysqldump默认启用了一个新标志, 通过 --column-statistics=0 来关闭它.#解决方案: mysqldump --column-statistics=0 -h主机ip -P端口号 -u数据库用户名 -p数据库密码 数据库名称 > 想要备份的文件名称.sql原文链接:https://blog.csdn.net/ZRHZRHH/article/details/110134222
2023年12月06日
26 阅读
0 评论
0 点赞
2023-12-06
MySQL 主从同步(实操)
介绍本文章实操基于 从机读取主机binlog二进制文件,执行相同操作实现数据一致原理(关于从机slave数据与主机master数据不一致不同步等故障不在本文介绍中)关于主从服务器的环境不限要求 Centos或者Windows server均可 主服务器配置1.修改my.cnf配置文件[mysqld] # 主数据库端ID号 server-id = 1 # 开启二进制日志 log-bin = mysql-bin # 需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可 binlog-do-db = test_db # 以下配置按需添加 #将从服务器从主服务器收到的更新记入到从服务器自己的二进制日志文件中 log-slave-updates #控制binlog的写入频率。每执行多少次事务写入一次(这个参数性能消耗很大,但可减小MySQL崩溃造成的损失) sync_binlog = 1 #这个参数一般用在主同步中,用来错开自增值, 防止键值冲突 auto_increment_offset = 1 #这个参数一般用在主同步中,用来错开自增值, 防止键值冲突 auto_increment_increment = 1 #二进制日志自动删除的天数,默认值为0,表示“没有自动删除”,启动时和二进制日志循环时可能删除 expire_logs_days = 10 #将函数复制到slave log_bin_trust_function_creators = 1log-slave-updates该参数我的理解是告诉slave是否将master中binlog日志中的操作同步到本身binlog日志中。该参数不写 默认是FALSE Slave读取到master中binlog操作不记录本身binlog。所以说主从同步设置成 A>B>C三层级形式。 A是master , B是slave 读取A的数据同步,C是slave 读取B的数据同步。此时就需要该参数。binlog-do-db 二进制日志记录的数据库(多库逗号分割)binlog-ignore-db 二进制日志中忽略数据库(多库逗号分割)2.重启mysql服务#手动重启 #指令重启(系统环境配置过mysql才适用) systemctl restart mysqld3.创建允许从服务器同步数据的账号#进入mysql mysql -uroot -p123456 grant replication slave on *.* to 'slave'@'%' identified by '123456'; # 刷新权限 flush privileges; 4.查看主服务器数据库状态show master status\G;需要记录下 File 文件(binlog日志记录所在券)和 Position 逻辑位置(file是一个二进制文件该参数记录当前数据插入位置)这两个参数在从机设置中需要告知从服务器配置1.编辑数据库配置文件vim /etc/my.cnf # 在[mysqld]后添加以下配置 # 主数据库端ID号 server-id = 2 # 开启二进制日志 log-bin = mysql-bin # [可选]如果从数据库名称要和主数据库名称不一样的话一定要加上这一条配置 replicate-rewrite-db = test1 -> test2 # [可选]同步指定数据库 replicate-do-db = test1 # [可选]排除指定数据库 replicate-ignore-db = test22.重启从数据库3.进入数据库执行同步命令/** 配置同步服务器 master_host 主服务器ip master_user 主服务器同步账户(在主服务器配置时创建的) master_log_file 同步文件位置 */ change master to master_host='xx.xx.xx.xx',master_user='slave',master_password='123456',master_log_file='mysql-bin.000011',master_log_pos=7418; # 启动同步功能 start slave; # 查看同步状态,Slave_IO_Running及Slave_SQL_Running的值都是YES代表配置成功 show slave status\G;在此处master\_log\_file参数填写主库同步状态的 File参数,master\_pos\_pos参数填写主库同步状态的 Position参数或者0(自动获取)。查看从库同步状态只需要关注 Slave\_IO\_Running参数 和 Slave\_SQL\_Running参数 均是 Yes即可 表示主从配置成功
2023年12月06日
37 阅读
0 评论
0 点赞
2023-07-08
laravel基础-链式操作返回值
DB Facades$users = DB::table('users')->get(); 返回值:数组结果,其中每一个结果都是 StdClass $user = DB::table('users')->first(); 返回值:单个 StdClass 实例 //例如可以取值$users->id;注意: StdClass对象 => 基础对象Eloquent1, $user = User::first(); 返回值:Eloquent 对象 2, $user = User::find(); 返回值:Eloquent 对象 3, $users = User::get(); 返回值:Eloquent 集合 4, $users = User::all(); 返回值:Eloquent 集合 5, $user = User::create($data); 返回值:Eloquent 对象 6, $user = new User(); $user->name = "admin" $user->save(); 返回值:Eloquent 对象 7, $result = User::insert($data); 返回值:bool 8, $result = $user->delete(); 返回值:bool 9, $count = User::destroy([1, 2]); 返回值:删除记录数 10, $count = User::where('id', '>', 1)->delete(); 返回值:删除记录数 11, $count = User::where('id', '>', 10)->update(['status' => 1]);返回值:更新记录数 12, $count = User::where('id', '>', 10)->increment('age', 1); 返回值:更新记录数注意:Eloquent 模型对象(Model 对象) => 和模型相关的类对象Eloquent 集合 => 可以简单理解为对象数组,里面的每一个元素都是一个Model 对象
2023年07月08日
52 阅读
0 评论
0 点赞
2023-05-22
Dcat菜单列表重写
前提在项目中使用的dcatadmin框架多用户模式,只有一个单后台,用户角色分为:administrator(超管), member(会员), sub_account(会员子账号)每个会员及其子账号 只能看见自己创建的自定义表单在菜单显示(例如A会员和A会员创建的A1子会员,A2子会员 大家登录后看见都是一样的, 但是A会员和B会员看见的自定义表单菜单是不一样的)。仔仔细细看了下文档 只能动态添加菜单,可是不能根据当前登录用户来决定菜单是否显示,此时脑中浮现两种方式,方式一,在创建自定义表单的时候,同时往admin_menu,admin_role,admin_role_users等表中插入菜单关联数据需要操作3-5个关系表(菜单,角色,权限及其关系表),然后每个用户都创建一个单独的与用户对应的角色,在将角色和菜单关联,让dcat来自动显示是否显示。 但是这种做需要同时操作的数据库表多张,关系繁琐弊端较多 妥妥的下下测。方式二,重构菜单列表,在渲染菜单列表的时候使用文档中通过Menu::add接口动态添加菜单 然后我也就不需要在把创建的自定义表单,单独的存入admin_menu中菜单中。仅仅只需要获取当前登录用户然后在原本菜单列表渲染后面动态add一份自定义表单即可。创建任务:在/App/Admin中重写菜单列表渲染下面即是我阅读dcat源码后进行的操作过程:复制数据格式源位置/vendor/dcat/laravel-admin/src/Layout/Menu.php复制到/app/Admin/Layout/Menu.php<?php /** * 菜单列表重写 */ namespace App\Admin\Layout; //namespace Dcat\Admin\Layout; use Dcat\Admin\Admin; use Dcat\Admin\Support\Helper; use Illuminate\Support\Facades\Lang; class Menu { protected static $helperNodes = [ [ 'id' => 1, 'title' => 'Helpers', 'icon' => 'fa fa-keyboard-o', 'uri' => '', 'parent_id' => 0, ], [ 'id' => 2, 'title' => 'Extensions', 'icon' => '', 'uri' => 'auth/extensions', 'parent_id' => 1, ], [ 'id' => 3, 'title' => 'Scaffold', 'icon' => '', 'uri' => 'helpers/scaffold', 'parent_id' => 1, ], [ 'id' => 4, 'title' => 'Icons', 'icon' => '', 'uri' => 'helpers/icons', 'parent_id' => 1, ], ]; protected $view = 'admin::partials.menu'; public function register() { if (! admin_has_default_section(Admin::SECTION['LEFT_SIDEBAR_MENU'])) { admin_inject_default_section(Admin::SECTION['LEFT_SIDEBAR_MENU'], function () { $menuModel = config('admin.database.menu_model'); return $this->toHtml((new $menuModel())->allNodes()->toArray()); }); } //================================================================================ //在此处追加-添加自定义的菜单 $this->add([ [ 'id' => 400, // 此id只要保证当前的数组中是唯一的即可 'title' => '测试菜单999', 'icon' => 'fa-file-text-o', 'uri' => '', 'parent_id' => 0, 'permission_id' => '7', // 与权限绑定 'roles' => 'user2', // 与角色绑定 ], [ 'id' => 401, // 此id只要保证当前的数组中是唯一的即可 'title' => '测试菜单-item', 'icon' => 'fa-file-text-o', 'uri' => '', 'parent_id' => 400, 'permission_id' => '7', // 与权限绑定 'roles' => 'user2', // 与角色绑定 ] ],20); //=================================================================================== //\Illuminate\Support\Facades\Log::debug('111111111'); if (config('app.debug') && config('admin.helpers.enable', true)) { $this->add(static::$helperNodes, 20); //$this->add(static::$helperNodes, 20); //$this->add(static::$helperNodes, 20); //$this->add(static::$helperNodes, 20); //$this->add(static::$helperNodes, 20); } } /** * 增加菜单节点. * * @param array $nodes * @param int $priority * @return void */ public function add(array $nodes = [], int $priority = 10) { admin_inject_section(Admin::SECTION['LEFT_SIDEBAR_MENU_BOTTOM'], function () use (&$nodes) { return $this->toHtml($nodes); }, true, $priority); } /** * 转化为HTML. * * @param array $nodes * @return string * * @throws \Throwable */ public function toHtml($nodes) { $html = ''; foreach (Helper::buildNestedArray($nodes) as $item) { $html .= $this->render($item); } return $html; } /** * 设置菜单视图. * * @param string $view * @return $this */ public function view(string $view) { $this->view = $view; return $this; } /** * 渲染视图. * * @param array $item * @return string */ public function render($item) { return view($this->view, ['item' => &$item, 'builder' => $this])->render(); } /** * 判断是否选中. * * @param array $item * @param null|string $path * @return bool */ public function isActive($item, ?string $path = null) { if (empty($path)) { $path = request()->path(); } if (empty($item['children'])) { if (empty($item['uri'])) { return false; } return trim($this->getPath($item['uri']), '/') == $path; } foreach ($item['children'] as $v) { if ($path == trim($this->getPath($v['uri']), '/')) { return true; } if (! empty($v['children'])) { if ($this->isActive($v, $path)) { return true; } } } return false; } /** * 判断节点是否可见. * * @param array $item * @return bool */ public function visible($item) { if ( ! $this->checkPermission($item) || ! $this->checkExtension($item) || ! $this->userCanSeeMenu($item) ) { return false; } $show = $item['show'] ?? null; if ($show !== null && ! $show) { return false; } return true; } /** * 判断扩展是否启用. * * @param $item * @return bool */ protected function checkExtension($item) { $extension = $item['extension'] ?? null; if (! $extension) { return true; } if (! $extension = Admin::extension($extension)) { return false; } return $extension->enabled(); } /** * 判断用户. * * @param array|\Dcat\Admin\Models\Menu $item * @return bool */ protected function userCanSeeMenu($item) { $user = Admin::user(); if (! $user || ! method_exists($user, 'canSeeMenu')) { return true; } return $user->canSeeMenu($item); } /** * 判断权限. * * @param $item * @return bool */ protected function checkPermission($item) { $permissionIds = $item['permission_id'] ?? null; $roles = array_column(Helper::array($item['roles'] ?? []), 'slug'); $permissions = array_column(Helper::array($item['permissions'] ?? []), 'slug'); if (! $permissionIds && ! $roles && ! $permissions) { return true; } $user = Admin::user(); if (! $user || $user->visible($roles)) { return true; } foreach (array_merge(Helper::array($permissionIds), $permissions) as $permission) { if ($user->can($permission)) { return true; } } return false; } /** * @param string $text * @return string */ public function translate($text) { $titleTranslation = 'menu.titles.'.trim(str_replace(' ', '_', strtolower($text))); if (Lang::has($titleTranslation)) { return __($titleTranslation); } return $text; } /** * @param string $uri * @return string */ public function getPath($uri) { return $uri ? (url()->isValidUrl($uri) ? $uri : admin_base_path($uri)) : $uri; } /** * @param string $uri * @return string */ public function getUrl($uri) { return $uri ? admin_url($uri) : $uri; } }注册在/app/Providers/AppServiceProvider.php注册上一步的php文件use App\Admin\Layout\Menu; ... public function register() { //注册菜单列表 $this->app->singleton('admin.menu', Menu::class); }复制模板文件原模板所在位置/vendor/dcat/laravel-admin/resoures/views/partials/menu.blade.php复制到/resoures/views/vendor/admin/partials/menu.blade.php@php $depth = $item['depth'] ?? 0; $horizontal = config('admin.layout.horizontal_menu'); $defaultIcon = config('admin.menu.default_icon', 'feather icon-circle'); @endphp @if($builder->visible($item)) @if(empty($item['children'])) <li class="nav-item"> <a data-id="{{ $item['id'] ?? '' }}" @if(mb_strpos($item['uri'], '://') !== false) target="_blank" @endif href="{{ $builder->getUrl($item['uri']) }}" class="nav-link {!! $builder->isActive($item) ? 'active' : '' !!}"> {!! str_repeat(' ', $depth) !!}<i class="fa fa-fw {{ $item['icon'] ?: $defaultIcon }}"></i> <p> {!! $builder->translate($item['title']) !!} </p> </a> </li> @else <li class="{{ $horizontal ? 'dropdown' : 'has-treeview' }} {{ $depth > 0 ? 'dropdown-submenu' : '' }} nav-item {{ $builder->isActive($item) ? 'menu-open' : '' }}"> <a href="#" data-id="{{ $item['id'] ?? '' }}" class="nav-link {{ $builder->isActive($item) ? ($horizontal ? 'active' : '') : '' }} {{ $horizontal ? 'dropdown-toggle' : '' }}"> {!! str_repeat(' ', $depth) !!}<i class="fa fa-fw {{ $item['icon'] ?: $defaultIcon }}"></i> <p> {!! $builder->translate($item['title']) !!} @if(! $horizontal) <i class="right fa fa-angle-left"></i> @endif </p> </a> <ul class="nav {{ $horizontal ? 'dropdown-menu' : 'nav-treeview' }}"> @foreach($item['children'] as $item) @php $item['depth'] = $depth + 1; @endphp @include('admin::partials.menu', ['item' => $item]) @endforeach </ul> </li> @endif @endif注意:复制出来的文件不一定按着我这个路径存放,只需要在代码关联中引用正确自动加载就能够加载出来。就上述三个文件改动即可,然后具体的数据查询根据业务需求去写即可,可以是在/app/Admin/Layout/Menu.php中 56行后面接着写,也可以将数据查询写到Models中,如果在Models中重写需要在/config/admin.php 中 'menu_model' => Dcat\Admin\Models\Menu::class, 改成自定义的模型位置。总结使用这种定义好的后端框架确实是开发迅速,但是局限性很高,如果有些特殊的需求或者效果还是需要自定义。多翻翻源码还有帮助的。此篇重构dcat菜单列表我觉得还是可以在优化一下的。仅仅记录下解决方法,如果您有更好的方式欢迎告知我。
2023年05月22日
54 阅读
0 评论
1 点赞
2022-11-14
查杀kswapd0挖矿木马
记录下挖矿病毒服务器是物理机,所有端口都是暴露开放的。服务器挖矿 导致 负载cpu内存等异常,通过排查确定是 kswapd0 挖矿木马排查过程如下:top -cPID: 19980 和 10630 cpu使用率最多进程PID:10630 ./masscan 为端口扫描工具进程PID:19980 ./kswapd0 为木马挖矿脚本通过PID进程查询文件路径 #ls -la /proc/[PID]/exe ls -la /proc/19980/exe # [root@localhost ~]# ls -la /proc/19980/exe # lrwxrwxrwx 1 root root 0 11月 13 22:42 /proc/19980/exe -> /root/.configrc/a/kswapd0 查看文件编辑时间 stat kswapd0 呵,还是新鲜热乎的呢。猜测是脚本自动修改执行根据kswapd0进程的PID查找相关的网络连接netstat -natupl | grep [PID]怀疑是自动执行,查询下定时任务[root@localhost a]# /var/spool/cron/root -bash: /var/spool/cron/root: 权限不够 [root@localhost a]# crontab -l 1 1 */2 * * /root/.configrc/a/upd>/dev/null 2>&1 @reboot /root/.configrc/a/upd>/dev/null 2>&1 5 8 * * 0 /root/.configrc/b/sync>/dev/null 2>&1 @reboot /root/.configrc/b/sync>/dev/null 2>&1 0 0 */3 * * /tmp/.X206-unix/.rsync/c/aptitude>/dev/null 2>&1定位到/tmp/.X206-unix/.rsync/ 目录删除kill掉病毒文件进程kill -9 [PID]查询相应资料说该病毒 会生成/root/.ssh公钥文件进行连接操作等步骤查看病毒所使用的ssh密钥文件找到删除即可病毒结构经过网上查证,该病毒种类繁多,文件位置基本不一样/root/.configrc/* 病毒所在目录 /root/.ssh/病毒公钥 /tmp/.X25-unix/.rsync/* 病毒运行缓存文件 /tmp/.X25-unix/dota3.tar.gz 病毒压缩包 /root/.configrc/a/kswapd0 病毒主程序 ==========病毒相关计划任务========== 1 1 */2 * * /root/.configrc/a/upd>/dev/null 2>&1 @reboot /root/.configrc/a/upd>/dev/null 2>&1 5 8 * * 0 /root/.configrc/b/sync>/dev/null 2>&1 @reboot /root/.configrc/b/sync>/dev/null 2>&1 0 0 */3 * * /tmp/.X25-unix/.rsync/c/aptitude>/dev/null 2>&1总结一下大致的处置流程:1.直接kill掉kswapd0的进程ID,后续观察服务,然后 清理计划任务: crontab -e2.删除/root/ 目录下的.configrc病毒文件夹3.删除/root/ 目录下的.ssh病毒公钥文件夹4.删除/tmp/.X25-unix/或/dev/shm/.X19273/病毒运行文件。其实在定位到进程文件的时候,就在网上搜了下该病毒对应的处置思路。附上相关链接:https://bbs.sangfor.com.cn/forum.php?mod=viewthread&tid=148169http://www.hackdig.com/12/hack-243523.htm
2022年11月14日
103 阅读
0 评论
0 点赞
2022-10-05
MySQL简单记录下指令导入数据库
记录一下 使用source指令还原数据操作在web端或者 第三方数据库连接软件 导入.sql文件时 执行时间过长导致执行失败。我所使用的系统和环境为 CentOS 7.9.2009 x86_6 + 宝塔 在phpMyAdmin 网页管理中导入 data.sql.zip 由于执行时间过长 导致页面502BadGateway,(phpMyAdmin还有一个限制,上次压缩包不能超过50Mb)然后我又尝试在客户端软件DBeaver中导入sql文件不出意外导入失败了,由于DBeaver使用JAVA编写的客户端报错提示java运行内存溢出。最后尝试一下使用mysql指令对备份文件进行还原。由于使用的是宝塔LNMP环境 可以直接在shell控制台执行mysql命令附录mysql基本操作指令:-- 查看所有库 show databases; -- 使用库 use 数据库名; --创建库 create database 库名; --修改库的字符编码集,需要重启mysql alter database 数据库名 character set utf8; -- 删除数据库 drop database 数据库名; -- 查看当前在使用哪个库 select database(); -- 查看所有表 show tables; -- 查看表结构 desc 表名; -- 删除表 drop table 表名; -- 快删除所有表,但不删除库(有层级关联需要执行两遍) select concat('drop table ',table_name,';') from information_schema.TABLES where table_schema='数据库名';操作步骤:-- 0.将data.sql文件复制到数据服务器上 /home/data.sql -- 1.连接数据库 mysql -uroot -ppassword -- 2.选择数据库 use 数据库名; -- 3.导入数据 source /home/data.sql -- 4.等待导入完成mysql导入导出命令https://blog.csdn.net/weixin_45299340/article/details/121380058
2022年10月05日
101 阅读
0 评论
0 点赞
2022-09-04
[laravel] 监听方式记录SQL日志
创建监听器php artisan make:listener QueryListener --event=Illuminate\Database\Events\QueryExecuted打开app/Providers/EventServiceProvider.php添加引导protected $listen = [ 'Illuminate\Database\Events\QueryExecuted' => [ 'App\Listeners\QueryListener', ] ];打开app/Listeners/QueryListener#引入log use Illuminate\Support\Facades\Log; #handle方法添加代码: public function handle(QueryExecuted $event) { if (env('APP_DEBUG')) { $sql = str_replace("?", "'%s'", $event->sql); $log = vsprintf($sql, $event->bindings); $log = '[' . date('Y-m-d H:i:s') . '] ' . $log . PHP_EOL; $logDir = storage_path('logs/sql'); // if (!is_dir($logDir)) { // mkdir($logDir, 0777, true); // } file_put_contents($logDir, $log, FILE_APPEND); //Log::channel('sql')->info($log); #未添加sql日志通道 /* 'sql'=>[ 'driver' => 'daily', 'level' => 'debug', 'path' => storage_path('logs/sql/log.log'), ], */ } }补充-添加日志通道在写入日志使用Log::channel('sql')->info($log); 需要配置下日志记录通道在config/logging.php加入以下内容:'sql'=>[ 'driver' => 'daily', 'level' => 'debug', 'path' => storage_path('logs/log.log'), ],
2022年09月04日
101 阅读
0 评论
0 点赞
2022-08-19
[tymon]JWT-AUTO 翻译
[tymon]JWT-AUTO 翻译参考链接:jwt官网 https://jwt-auth.readthedocs.io/en/develop/laravel加载jwt参考 https://learnku.com/laravel/t/27760拉起最新版本:composer require tymon/jwt-auth注意:laravel-5.4版本以下将服务提供者添加到配置文件中的providers数组中config/app.php,如下所示:'providers' => [ ... Tymon\JWTAuth\Providers\LaravelServiceProvider::class, ]发布配置php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"此时自动生成一个config/jwt.php文件,允许配置此包的基础知识。生成密钥php artisan jwt:secret此步会更新.env文件JWT_SECRET={}laravel配置jwt更新用户模型需要在原本的User模型上实现getJWTIdentifier()和 getJWTCustomClaims()<?php namespace App; use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements JWTSubject { use Notifiable; // Rest omitted for brevity /** * Get the identifier that will be stored in the subject claim of the JWT. * * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * Return a key value array, containing any custom claims to be added to the JWT. * * @return array */ public function getJWTCustomClaims() { return []; } }配置身份验证保护注意此项需要laravel5.2及更高版本是时才有效。在该config/auth.php文件中,您需要进行一些更改来配置 Laravel 以使用jwt防护来支持您的应用程序身份验证。对文件进行下述更改:'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ], ... 'guards' => [ 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], ],这里我们告诉api守卫使用jwt驱动程序,我们将api守卫设置为默认值。我们现在可以使用 Laravel 内置的 Auth 系统,而 jwt-auth 在幕后工作!添加一些基本的认证路由routes/api.phpRoute::group([ 'middleware' => 'api', 'prefix' => 'auth' ], function ($router) { Route::post('login', 'AuthController@login'); Route::post('logout', 'AuthController@logout'); Route::post('refresh', 'AuthController@refresh'); Route::post('me', 'AuthController@me'); });创建AuthController命令创建php artisan make:controller AuthController添加以下内容<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use App\Http\Controllers\Controller; class AuthController extends Controller { /** * Create a new AuthController instance. * * @return void */ public function __construct() { $this->middleware('auth:api', ['except' => ['login']]); } /** * Get a JWT via given credentials. * * @return \Illuminate\Http\JsonResponse */ public function login() { $credentials = request(['email', 'password']); if (! $token = auth('api')->attempt($credentials)) { return failed('账号或者密码错误'); //return response()->json(['error' => 'Unauthorized'], 401); } $data = array( 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60 ); return success($data,'登录成功'); //return $this->respondWithToken($token); } /** * Get the authenticated User. * * @return \Illuminate\Http\JsonResponse */ public function me() { return response()->json(auth()->user()); } /** * Log the user out (Invalidate the token). * * @return \Illuminate\Http\JsonResponse */ public function logout() { auth()->logout(); return success([],'已成功注销'); //return response()->json(['message' => 'Successfully logged out']); } /** * Refresh a token. * * @return \Illuminate\Http\JsonResponse */ public function refresh() { return $this->respondWithToken(auth('api')->refresh()); } /** * Get the token array structure. * * @param string $token * * @return \Illuminate\Http\JsonResponse */ protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60 ]); } } 注意上面代码中使用了自动封装的助手函数 success() 和 failed()封装方式详见这篇文章测试最后就可以直接访问一下http://{HOST}/auth/login会得到类似参数:{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ", "token_type": "bearer", "expires_in": 3600 }验证身份有多种方式通过授权头方式Authorization: Bearer eyJhbGciOiJIUzI1NiI...通过查询字符串参数http://example.dev/me?token=eyJhbGciOiJIUzI1NiI...补充关于测试环境和开发模式切换引发报错Auth guard driver [api] is not defined 尝试使用composer install 或者 composer update补全丢失依赖文件
2022年08月19日
162 阅读
0 评论
0 点赞
2022-08-02
MySQL统计数据库使用容量
直接上代码select table_schema as '表名字', concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as '数据使用/MB', concat(round(sum(INDEX_LENGTH/1024/1024),2),'MB') as '索引使用/MB', concat(round((sum(DATA_LENGTH)+sum(INDEX_LENGTH))/1024/1024,2),'MB') as '总数据容量/MB' from information_schema.TABLES group by table_schema; MySQL自带访问数据库元数据的方式:information_schema.tables 获取所有数据库#查看Mysql所有数据库中数据表的名称、数据库注释、创建时间(mysql自带的和自定义的都会查询出来) select table_name, table_comment, create_time, update_time from information_schema.tablestable_schema 是数据库的名称table_name 是具体的表名。table_type 表的类型。#获取某个数据库中的所有表的表名、表类型、引擎等等 select table_name, table_type, engine from information_schema.tables where table_schema = '{数据库名}' order by table_name desc;select database() 获取当前数据库下的所有表#获取 当前数据库下的所有表名、表注释、创建及更新时间。 select table_name, table_comment, create_time, update_time from information schema.tables where table_schema (select database());concat(str1, str2, str3)将多个字符串连接成一个字符串注意其中有一个null,返回值也是null。data_length : 存储数据大小index_length : 索引数据大小
2022年08月02日
55 阅读
0 评论
0 点赞
1
2
...
7