前言

咔咔目前所做的项目是一个saas系统,在开发新功能之后,需要为用户角色添加相应的权限,这时整个系统的所有用户都需要添加相应的权限。

因为以前系统的缺陷现在只能用脚本来处理这些工作,所以接下来咔咔将向你介绍如何编写安全可靠的PHP脚本,以及如何事先设计好这个功能,踩过一个坑直接把它埋起来

一、如何写一份安全又可靠的PHP脚本

1-1 设置合理的内存

PHP中使用memory_limit为每个进程设置内存,跑脚本的内存给256M或512M。

通过设置内存来防止脚本执行死循环占用大量的内存,导致系统崩溃。

在文件开头写入ini_set('memory_limit', '512M');即可。

1-2 可接收命令行传参

在PHP中接命令行的参数为$argv,下标0是文件名,下标1为你传入的参数。

简单来说就是先创建一个 index.php文件,然后打印出$argv

执行index.php文件php index.php kaka,打印出来的数据与上面介绍的数组形式完全一样。第一个值是执行的文件名,第二个参数就是携带给脚本的参数。

之前写了一篇laravel中给命令行携带参数不了解一下吗?可以看看,当时是rabbitmq路由模式遇到问题才知道的这个参数,如今在写脚本就可以直接用了。

1-3 使用while死循环执行

$id = !empty($argv[1]) ? $argv[1] : 0;
while(true){
    $sql = "select * from user id > $id  order by id asc limit 10000";
    $res = 执行$sql语句;
    if(empty($res)){
        break;
    }
    foreach ($res as $k => $v) {
     // 这个id保存每次执行的值
        $id = $v['id'];
        $checkDataSql = "检测数据是否已存在";
    // 不存在时在进行添加数据
        if(!$checkSql){
            $sql = "insert into user ...";
            $res = "执行添加操作";
            // 返回最后执行的主键ID
            echo $res."\n";
        }
    }
    // 删除此次的变量,防止内存溢出
    unset($res);
}
echo 'ok';

简单的解释一下这份代码

  • 接受命令参数,此参数用于防止脚本执行一半挂掉,可以输入参数继续执行。
  • 使用while执行死循环逻辑
  • 获取需要添加权限的数据,每次查询10000行。
  • 死循环退出条件是查询不到需要添加权限的数据。
  • 循环处理每次查询的10000行数据。
  • 将查询出来的数据ID循环一次就赋值给while外层的ID,防止脚本挂掉知道从哪条数据继续执行。
  • 做一步检测操作,判断此条数据是否已经存在将要给添加的权限。不存在时再进行添加操作。
  • 最后一步也是最重要的一步将添加完成的主键ID返回到终端,脚本挂掉直接用这个ID作为参数继续执行。
  • 删除或者10000行数据的变量,防止内存溢出。
  • 最后一步也是最重要的数据处理完成后需要返回一个标识,知道此次脚本已经执行完成了。

这里举的例子的是添加,若你的数据量大的情况下可以进行批量添加、修改。

这份脚本还不是很完善,如你有更好的想法那咱们评论区见。

二、如何提前设计好类似此种情况

1-1 使用脚本刷数据的缺点

  • 新员工对业务不熟悉,数据刷错后恢复数据工作量更大
  • 前期用户基数少没感觉,用户量起来后每次执行脚本会花费很长时间
  • 用户量大之后MySQL深度分页查询非常慢,会人为造成慢查询影响正常用户使用
  • 在你刷数据的同时会有新用户注册进来,非常容易造成数据库死锁。

为什么会产生死锁?

例如你目前的数据数据是这样的,id、authority_info、name

insert into t values(1,5,5),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

脚本执行语句为update role set authority_info=authority_info+1 where id = 7

此条语句为等值查询会退化为间隙锁,加锁范围为(5,10),若此时来了一个用户执行语句为insert into role (8,8,8)很遗憾是执行不成功的。

update将(5,10)的数据加了间隙锁,在没有释放锁的情况下,这个范围的所有数据是无法添加的。

当然这种情况仅在无主键索引的情况下会产生,因为主键索引的等值查询会退化为行锁。

总之使用脚本刷数据是百害而无一利的,接下来看看如何处理这种情况。

1-2 应用场景

每一家公司注册后,默认有几个角色,如超管、子管、财务、行政、人事等,所有权限都绑定在相应的角色下,使用单条记录方式。

既然需要添加一个CUI功能模块,就需要添加此模块对应的权限,默认情况下为所有租户相应的所有角色添加这个权限。

每一个租户对应角色的权限都存储在角色表中,所有权限信息是在一个json串中存储,并切维护了一个更新时间。

那么我们就以获取权限为切入点,主系统单独维护一个权限表,来看看这个过程是怎样的。

1-2 方案落地

那么如何在这个设计上进行优化,确保后期不再使用脚本进行刷数据,而是让用户自主触发。

role表结构数据如下

系统表

系统添加新功能需要设置权限时,将权限名以json存储至系统表的auth_info中,每次更新权限都添加一条数据。

用户登录后获取role表的更新时间,去系统表中做判断将大于role时间的数据拿出来,将查询出来的权限合并到role表中,并更新这条记录的更新时间。

并将新增的权限维护至应用初始化中,新注册的用户需将所有的权限给添加上,这点根据自身系统看是否需要维护。

1-4 方案弊端

此方案虽然解决了每次添加新权限需要执行脚本,但不可避免用户每次登录获取权限时都需要使用自身的权限时间跟系统权限时间做比对。

无形中会多进行一次查询,这也是咔咔目前能想到的方案,你要是有更好的方案可以探讨一下。

三、总结

本文围绕实际业务进行讨论了脚本如何写、设计缺陷如何后期弥补,在脚本中一定要使用正序(防止新用户注册进来)这点相信大家都清楚。

方案在我看来还不是最优的,你要是有更好的思路,可以在评论区扩展一下。

坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念。愿文章在偌大的互联网上能给你带来一点帮助,我是咔咔,下期见。

如何写出安全又可靠的PHP脚本的更多相关文章

  1. 如何用java写出无副作用的代码

    搞java的同学们可能对无副作用这个概念比较陌生,这是函数式编程中的一个概念,无副作用的意思就是: 一个函数(java里是方法)的多次调用中,只要输入参数的值相同,输出结果的值也必然相同,并且在这个函 ...

  2. 如何写出好的Java代码?

    1. 优雅需要付出代价.从短期利益来看,对某个问题提出优雅的解决方法,似乎可能花你更多的时间.但当它终于能够正确执行并可轻易套用于新案例中,不需要花上数以时计,甚至以天计或以月计的辛苦代价时,你会看得 ...

  3. JAVA语言之怎样写出高性能的Java代码?

    本文主要向大家介绍了JAVA语言之怎样写出高性能的 Java 代码?通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法.我 ...

  4. 如何写出一个让人很难发现的bug?

    程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因为我的眼里常含bug. 那么如何写出一个让(坑)人(王)很(之)难(王)发现的bug呢? - 1 -新手开发+ ...

  5. 参考sectools,每个人至少查找5种安全工具、库等信息并深入研究至少两种并写出使用教程

    1.Nessus Nessus是免费网络漏洞扫描器,它可以运行于几乎所有的UNIX平台之上.它不仅能永久升级,还免费提供多达11000种插件(但需要注册并接受EULA-acceptance--终端用户 ...

  6. [label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码

    7 steps to better JavaScript 原文链接: http://www.creativebloq.com/netmag/7-steps-better-javascript-5141 ...

  7. 浅谈如何写出一个让(坑)人(王)很(之)难(王)发现的bug

    该文章内容来自脚本之家,原文链接:https://www.jb51.net/news/598404.html 程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因 ...

  8. IDEA 插件推荐 —— 让你写出好代码的神器!

    概述 今天介绍的插件主要是围绕编码规范的.有追求的程序员,往往都有代码洁癖,要尽量减少代码的「坏味道」. 代码静态检查是有很多种类,例如圈复杂度.重复率等.业界提供了很多静态检查的插件来识别这些不合规 ...

  9. 写出易调试的SQL(修订版)

    h4 { background: #698B22 !important; color: #FFFFFF; font-family: "微软雅黑", "宋体", ...

随机推荐

  1. rabbitMQ批量删除指定的队列

    首先进入到rabbitmq目录下的sbin目录 方法1: ./rabbitmqctl list_queues| grep helloQueue | awk '{print $1}' | xargs - ...

  2. 结合场景使用Redis缓存与数据库同步

    Redis缓存与MySQL数据库与同步 什么场景用到了Redis缓存? 1.广告数据 2.搜索时,分类品牌名称,分类名称和规格数据 3.购物车 4.支付 问题:如何实现? 1.广告数据 先查询Redi ...

  3. Linux 进程间传递文件描述符

    文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...

  4. S3C2440—1.熟悉裸机开发板

    文章目录 一.板载资源介绍 二.安装驱动及上位机 1.USB的驱动及上位机 2.eop驱动安装 3.安装烧录软件oflash 三.烧写开发板 1.预备知识 2.烧写裸板 3.使用u-boot烧写程序 ...

  5. SpringCloud升级之路2020.0.x版-18.Eureka的客户端核心设计和配置

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Eureka 客户 ...

  6. ☕【Java技术指南】「OpenJDK专题」想不想编译属于你自己的JDK呢?(Windows10环境)

    Win10下编译OpenJDK8 编译环境 Windows10专业版64位: 编译前准备 Tip: 以下软件的安装和解压目录尽量不要包含中文或空格,不然可能会出现问题 安装 Visual Studio ...

  7. 寻找写代码感觉(三)之使用 Spring Boot 编写接口

    一.前言 项目配置完之后,接着就是写接口了,那咱们就开始吧. 二.项目配置补充知识点 上篇文章写的是关于项目属性配置的一些知识,这里针对上次遗忘内容进行补充如下: 2.1.获取配置文件的值 在appl ...

  8. 【java虚拟机】内存溢出解决思路

    转自:https://blog.csdn.net/u013521220/article/details/79523633 内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知 ...

  9. Javascript - Vue - vuex

    vuex 这是一个与vue配套的公共数据管理工具,可以将一些需要共享的数据保存到vuex中,以此方便项目中的任何组件都可以从vuex中得到共享数据.cnpm i vuex -S 装包 读取数据 //在 ...

  10. 转:C语言自增自減问题总结

    C语言自增自減问题总结 在程序设计中,经常遇到"i=i+1"和"i=i-1"这两种极为常用的操作.C语言为这种操作提供了两个更为简洁的运算符,即++和--,分别 ...