# == 和 = 的问题
在连续判断中,如果我们把== 误写成 = 会带来很严重的后果。
如
if($a== 'a'){
}
if($a= 'c'){ //一次误写,就影响后续的变化
}
if($a == 'c'){
}
结果方法 :
比较值放前面 if('a' == $a)
# sqlite date类型查询的问题
朋友有个表
![](https://box.kancloud.cn/2016-02-29_56d3b60caa555.png)
开始 想查大于 1992-07-01的数据
按照原始的方法 HireDate > '1992-07-01'发现只查出 1993年的了
后来找了半天
最简单方法是 `select * from Mytable where HireDate >= '1/7/1992'`
按照他显示的格式查 当字符串去比较
# 数据库对比
介绍
本章主要介绍怎样对比数据库的表结构的差异,这里主要介绍使用mysqldiff工具来对比表结构的差异,其实在5.6版本之后通过查询information库中的系统表也能对比出来,但是mysqldiff还有一个好处就是可以直接生产差异的SQL语句这个功能就是我们需要利用的,而通过分析系统表要实现这个就比较难;接下来就来看看怎样使用这个工具。
语法
`mysqldiff --server1=user:pass@host:port:socket --server2=user:pass@host:port:socket db1.object1:db2.object1 db3:db4`
这个语法有两个用法:
db1:db2:如果只是指定数据库,那么就将两个数据库中互相缺少的对象显示出来,而对象里面的差异不进行对比;这里的对象包括表、存储过程、函数、触发器等。
db1.object1:db2.object1:如果指定了具体表对象,那么就会详细对比两个表的差异,包括表名、字段名、备注、索引、大小写等都有的表相关的对象。
接下来看一些主要的参数:
~~~
--server1:配置server1的连接
--server2:配置server2的连接
--character-set:配置连接时用的字符集,如果不显示配置默认使用“character_set_client”
--width:配置显示的宽度
--skip-table-options:这个选项的意思是保持表的选项不变,即对比的差异里面不包括表名、AUTO_INCREMENT,ENGINE, CHARSET等差异。
-d DIFFTYPE, --difftype:差异的信息显示的方式,有[unified|context|differ|sql](default: unified),如果使用sql那么就直接生成差异的SQL这样非常方便。
--changes-for=:例如--changes-for=server2,那么对比以sever1为主,生成的差异的修改也是针对server2的对象的修改。
--show-reverse:这个字面意思是显示相反的意思,其实是生成的差异修改里面同时会包含server2和server1的修改。
~~~
测试
~~~
use study;
create table test1
(id int not null primary key,
a varchar(10) not null,
b varchar(10),
c varchar(10) comment 'c',
d int
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test1';
create table test2
(id int not null ,
a varchar(10),
b varchar(5),
c varchar(10),
D int
)
ENGINE=myisam DEFAULT CHARSET=utf8 COMMENT='test2';
~~~
1.不使用--skip-table-options
`mysqldiff --server1=root:root@localhost --server2=root:root@localhost --changes-for=server2 --show-reverse --difftype=sql study.test1:study.test2`
![](https://box.kancloud.cn/5d8a2e8331cd74dee22384895dc81cca_1610x643.png)
2.使用--skip-table-options
![](https://box.kancloud.cn/580b5c676dee70e986f187ec298d6598_1786x595.png)
其实用SQL语句也可以达到查询的效果,这里就贴上平时用的对比语句。
~~~
###############################################################################################################################
##判断两个数据库相同表的字段不为空是否相同
select a.TABLE_SCHEMA,a.TABLE_NAME,a.COLUMN_NAME,a.COLUMN_TYPE,a.IS_NULLABLE,a.COLUMN_DEFAULT,b.TABLE_SCHEMA,b.TABLE_NAME,b.COLUMN_NAME,b.COLUMN_TYPE,b.IS_NULLABLE ,b.COLUMN_DEFAULT,b.COLUMN_COMMENT
from information_schema.`COLUMNS` a inner join information_schema.`COLUMNS` b
on a.TABLE_SCHEMA='db1' and b.TABLE_SCHEMA='db2'and a.TABLE_NAME=b.TABLE_NAME and a.COLUMN_NAME=b.COLUMN_NAME and a.IS_NULLABLE<>b.IS_NULLABLE
where a.IS_NULLABLE='NO';
################################################################################################################################
##判断两个数据库相同表的字段默认值是否相同
select a.TABLE_SCHEMA,a.TABLE_NAME,a.COLUMN_NAME,a.COLUMN_DEFAULT,b.TABLE_SCHEMA,b.TABLE_NAME,b.COLUMN_NAME,b.COLUMN_DEFAULT from information_schema.`COLUMNS` a
inner join information_schema.`COLUMNS` b on a.TABLE_SCHEMA='db1' and b.TABLE_SCHEMA='db2'
and a.TABLE_NAME=b.TABLE_NAME and a.COLUMN_NAME=b.COLUMN_NAME and a.COLUMN_DEFAULT<>b.COLUMN_DEFAULT;
#################################################################################################################################
##判断两个数据库相同表的字段数据类型是否相同,这里是判断数据类型不同如果要判断数据类型的长度不同需要用COLUMN_TYPE字段
select a.TABLE_SCHEMA,a.TABLE_NAME,a.COLUMN_NAME,a.DATA_TYPE,a.COLUMN_DEFAULT,b.TABLE_SCHEMA,b.TABLE_NAME,b.COLUMN_NAME,b.DATA_TYPE ,b.COLUMN_DEFAULT
from information_schema.`COLUMNS` a inner join information_schema.`COLUMNS` b on a.TABLE_SCHEMA='db1' and b.TABLE_SCHEMA='db2'
and a.TABLE_NAME=b.TABLE_NAME and a.COLUMN_NAME=b.COLUMN_NAME and a.DATA_TYPE<>b.DATA_TYPE;
##################################################################################################################################
##判断两个数据库相同表的中互相不存在的字段
select a.TABLE_SCHEMA,a.TABLE_NAME,a.COLUMN_NAME,a.DATA_TYPE,a.COLUMN_DEFAULT
from information_schema.`COLUMNS` a
where a.TABLE_SCHEMA='db1' and a.COLUMN_NAME NOT IN(SELECT b.COLUMN_NAME from information_schema.`COLUMNS` b where b.TABLE_SCHEMA='db2' and a.TABLE_SCHEMA='db1'
and a.TABLE_NAME=b.TABLE_NAME );
select a.TABLE_SCHEMA,a.TABLE_NAME,a.COLUMN_NAME,a.DATA_TYPE,a.COLUMN_DEFAULT
from information_schema.`COLUMNS` a
where a.TABLE_SCHEMA='db2' and a.COLUMN_NAME NOT IN(SELECT b.COLUMN_NAME from information_schema.`COLUMNS` b where b.TABLE_SCHEMA='db1' and a.TABLE_SCHEMA='db2'
and a.TABLE_NAME=b.TABLE_NAME );
####mysql没有full jion所以变相的多做了一次select查询,这种方法性能比较差,对于表比较多的数据库建议使用上面的分开查询
select b.TABLE_SCHEMA,b.TABLE_NAME,b.COLUMN_NAME,b.DATA_TYPE,c.TABLE_SCHEMA,c.TABLE_NAME,c.COLUMN_NAME,c.DATA_TYPE from
(select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,DATA_TYPE from information_schema.`COLUMNS` a where a.TABLE_SCHEMA in('db2','db1') )a left join
(select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,DATA_TYPE from information_schema.`COLUMNS` a where a.TABLE_SCHEMA in('db2')) b on a.TABLE_NAME=b.TABLE_NAME AND a.COLUMN_NAME=b.COLUMN_NAME left join
(select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,DATA_TYPE from information_schema.`COLUMNS` a where a.TABLE_SCHEMA in('db1')) c on a.TABLE_NAME=c.TABLE_NAME AND a.COLUMN_NAME=c.COLUMN_NAME
where b.COLUMN_NAME is null or c.COLUMN_NAME is null ;
#######################################################################################################################
##判断两个数据库互相不存在的表
select a.TABLE_SCHEMA,a.TABLE_NAME
from information_schema.TABLES a
where a.TABLE_SCHEMA='db1' and a.TABLE_NAME NOT IN(SELECT b.TABLE_NAME from information_schema.TABLES b where b.TABLE_SCHEMA='db2');
select a.TABLE_SCHEMA,a.TABLE_NAME
from information_schema.TABLES a
where a.TABLE_SCHEMA='db2' and a.TABLE_NAME NOT IN(SELECT b.TABLE_NAME from information_schema.TABLES b where b.TABLE_SCHEMA='db1');
select b.TABLE_SCHEMA,b.TABLE_NAME,c.TABLE_SCHEMA,c.TABLE_NAME from
(select TABLE_SCHEMA,TABLE_NAME from information_schema.TABLES a where a.TABLE_SCHEMA in('db2','db1') )a left join
(select TABLE_SCHEMA,TABLE_NAME from information_schema.TABLES a where a.TABLE_SCHEMA in('db2')) b on a.TABLE_NAME=b.TABLE_NAME left join
(select TABLE_SCHEMA,TABLE_NAME from information_schema.TABLES a where a.TABLE_SCHEMA in('db1')) c on a.TABLE_NAME=c.TABLE_NAME
where b.TABLE_NAME is null or c.TABLE_NAME is null ;
~~~
总结
这里没有演示对数据库的对比,数据库的对比显示的只是缺少的数据库对象,理解起来更加容易。
备注:
作者:pursuer.chen
博客:http://www.cnblogs.com/chenmh
本站点所有随笔都是原创,欢迎大家转载;但转载时必须注明文章来源,且在文章开头明显处给明链接。
# rtrim的问题
rtrim 是把trim 的字符串拆分开来 去匹配 因此 rtrim('3%3b', '%3b') 会连 3一块过滤了,什么都不留了。
# mysql数据精度问题
1.float类型
float列类型默认长度查不到结果,必须指定精度,比如
num float, insert into table (num) values (0.12); select * from table where num=0.12的话,empty set。
num float(9,7), insert into table (num) values (0.12); select * from table where num=0.12的话会查到这条记录。
mysql> create table tt
-> (
-> num float(9,3)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into tt(num)values(1234567.8);
Query OK, 1 row affected, 1 warning (0.04 sec)
注:超出字段范围,插入数据有误
mysql> select * from tt;
+-------------+
| num |
+-------------+
| 1000000.000 |
+-------------+
2 rows in set (0.00 sec)
***************************************************************************
注:通常在 linux 下安装完 mysql 后,默认的 sql-mode 值是空,在这种情形下 mysql 执行的是一种不严格的检查,例如日期字段可以插入 ’ 0000-00-00 00:00:00 ’这样的值,还有如果要插入的字段长度超过列定义的长度,那么 mysql 不会终止操作,而是会自动截断后面的字符继续插入操作。
我们发现插入的字符被自动截断了,但是如果我们本意希望如果长度超过限制就报错,那么我们可以设置 sql_mode 为 STRICT_TRANS_TABLES ,如下:
mysql> set session sql_mode='STRICT_TRANS_TABLES';
这样我们再执行同样的操作,mysql 就会告诉我们插入的值太长,操作被终止,如下:
mysql> insert into tt(num) values(1234567.8);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
***************************************************************************
mysql> insert into tt(num)values(123456.8);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+-------------+
| num |
+-------------+
| 1000000.000 |
| 123456.797 |
+-------------+
2 rows in set (0.00 sec)
注:小数位数不够,自动补齐,但是存在一个问题就是如上的近似值。
mysql> insert into tt(num)values(123456.867);
Query OK, 1 row affected (0.04 sec)
mysql> select * from tt;
+-------------+
| num |
+-------------+
| 1000000.000 |
| 123456.797 |
| 123456.867 |
+-------------+
3 rows in set (0.00 sec)
mysql> select * from tt where num=123456.867;
+------------+
| num |
+------------+
| 123456.867 |
+------------+
1 row in set (0.00 sec)
mysql> insert into tt(num)values(2.8);
Query OK, 1 row affected (0.04 sec)
mysql> select * from tt;
+-------------+
| num |
+-------------+
| 1000000.000 |
| 123456.797 |
| 123456.867 |
| 2.800 |
+-------------+
4 rows in set (0.00 sec)
mysql> select * from tt where num=2.8;
+-------+
| num |
+-------+
| 2.800 |
+-------+
1 row in set (0.00 sec)
mysql> insert into tt(num)values(2.888888);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+-------------+
| num |
+-------------+
| 1000000.000 |
| 123456.797 |
| 123456.867 |
| 2.800 |
| 2.889 |
+-------------+
5 rows in set (0.00 sec)
注:小数位数超了,自动取近似值。
--------------------------------------------------------------------------------------
2.double类型
mysql> create table tt(
-> num double(9,3)
-> );
Query OK, 0 rows affected (0.04 sec)
mysql> insert into tt(num) values(234563.9);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 234563.900 |
+------------+
1 row in set (0.00 sec)
mysql> insert into tt(num) values(2345623.2);
Query OK, 1 row affected, 1 warning (0.04 sec)
mysql> insert into tt(num) values(234563.2);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 234563.900 |
| 999999.999 |
| 234563.200 |
+------------+
2 rows in set (0.00 sec)
mysql> insert into tt(num) values(2.8);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 234563.900 |
| 999999.999 |
| 234563.200 |
| 2.800 |
+------------+
3 rows in set (0.00 sec)
FLOAT(M,D)或REAL(M,D)或DOUBLE PRECISION(M,D)。这里,“(M,D)”表示该值一共显示M位整数,其中D位位于小数点后面。
例如,定义为FLOAT(7,4)的一个列可以显示为-999.9999。MySQL保存值时进行四舍五入,因此如果在FLOAT(7,4)列内插入999.00009,近似结果是999.0001。
单精度浮点数(float)的尾数是用24bit表示的,双精度(double)浮点数的尾数是用53bit表示的,转换成十进制:
2^24 - 1 = 16777215
2^53 - 1 = 9007199254740991
由上可见,IEEE754单精度浮点数的有效数字二进制是24位,按十进制来说,是8位;双精度浮点数的有效数字二进制是53位,按十进制来说,是16 位。
# swoole+inotify实现异步实时文件监控
## inotify扩展介绍
inotify是Linux内核提供的一组系统调用,它可以监控文件系统操作,比如文件或者目录的创建、读取、写入、权限修改和删除等。
inotify使用也很简单,使用inotify_init创建一个句柄,然后通过inotify_add_watch/inotify_rm_watch增加/删除对文件和目录的监听。
PHP中提供了inotify扩展,支持了inotify系统调用。inotify本身也是一个文件描述符,可以加入到事件循环中,配合使用swoole扩展,就可以异步非阻塞地实时监听文件/目录变化。
## 安装inotify/swoole扩展
如果已经安装了inotify/swoole可以跳过此步骤。
~~~
pecl install swoole
pecl install inotify
~~~
操作成功后,修改php.ini,加入
~~~
extension=swoole.so
extension=inotify.so
~~~
查看扩展是否加载成功:
~~~
php -m | grep swoole
php -m | grep inotify
~~~
## inotify的使用
首先在当前目录创建一个inotify.data文件,示例就用来监听此文件。
~~~
//创建一个inotify句柄
$fd = inotify_init();
//监听文件,仅监听修改操作,如果想要监听所有事件可以使用IN_ALL_EVENTS
$watch_descriptor = inotify_add_watch($fd, __DIR__.'/inotify.data', IN_MODIFY);
while (true) {
//阻塞地读取数据
$events = inotify_read($fd);
if ($events) {
foreach ($events as $event) {
echo "inotify Event :".var_export($event, 1)."\n";
}
}
}
//释放inotify句柄
inotify_rm_watch($fd, $watch_descriptor);
fclose($fd);
~~~
修改inotify.data,就可以看到程序输出了信息。
~~~
echo "hello world" > inotify.data
inotify Event :array (
'wd' => 1,
'mask' => 2,
'cookie' => 0,
'name' => '',
)
~~~
## swoole+inotify异步非阻塞监听文件
~~~
//创建一个inotify句柄
$fd = inotify_init();
//监听文件,仅监听修改操作,如果想要监听所有事件可以使用IN_ALL_EVENTS
$watch_descriptor = inotify_add_watch($fd, __DIR__.'/inotify.data', IN_MODIFY);
//加入到swoole的事件循环中
swoole_event_add($fd, function ($fd) {
$events = inotify_read($fd);
if ($events) {
foreach ($events as $event) {
echo "inotify Event :" . var_export($event, 1) . "\n";
}
}
});
~~~
这里使用了swoole扩展提供swoole_event_add函数,将inotify句柄设置为非阻塞,并加入到epoll事件循环中。程序变成异步非阻塞模式。当有事件发生时才会执行inotify_read获取事件。没有事件发生时,程序可以执行其他的逻辑。
此程序与上一个同步阻塞例子的逻辑是相同的,向inotify写入内容时也会打印事件信息。区别在于swoole+inotify的程序是异步的。可以支持并发监听大量文件和目录,并且除了inotify操作之外还可以执行其他的IO操作。
* 关于inotify更多的信息可以到PHP官方网站中查看 [http://php.net/inotify](http://php.net/inotify)
* 关于swoole更多信息,请到swoole官方网站取了解 [http://www.swoole.com/](http://www.swoole.com/)
~~~ [sql]
-- ----------------------------
-- Table structure for oxygen_activity
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_activity`;
CREATE TABLE `oxygen_activity` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '名称',
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`sort` int(11) unsigned DEFAULT '0' COMMENT '排序 小在前面',
`status` tinyint(1) unsigned DEFAULT '1' COMMENT '1-开启 0-结束',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活动表';
-- ----------------------------
-- Table structure for oxygen_activity_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_activity_detail`;
CREATE TABLE `oxygen_activity_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`oxygen_activity_id` int(11) unsigned DEFAULT '0' COMMENT '活动id',
`product_id` int(11) unsigned DEFAULT NULL COMMENT '产品id',
`present` tinyint(1) unsigned DEFAULT '0' COMMENT '赠送 1-是 0-否',
`discount` float(3,2) unsigned DEFAULT '1.00' COMMENT '折扣 1.00 ',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活动明细表';
-- ----------------------------
-- Table structure for oxygen_balance
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_balance`;
CREATE TABLE `oxygen_balance` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(64) DEFAULT '' COMMENT '标题',
`money` float(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '金额',
`type` enum('收入','支出') DEFAULT '支出' COMMENT '类型',
`uid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
`order_id` int(11) unsigned DEFAULT '0' COMMENT '关联订单id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收支表';
-- ----------------------------
-- Table structure for oxygen_comment
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_comment`;
CREATE TABLE `oxygen_comment` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`order_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '订单id',
`content` text COMMENT '内容',
`uid` bigint(20) unsigned DEFAULT '0' COMMENT '用户uid',
`leased_poin_uid` bigint(20) unsigned DEFAULT '0' COMMENT '租赁点uid',
`leased_poin_score` tinyint(1) unsigned DEFAULT '0' COMMENT '租赁点评分1-5分',
`leased_point_server_uid` bigint(20) unsigned DEFAULT '0' COMMENT '租赁点服务员uid',
`leased_point_server_score` tinyint(1) unsigned DEFAULT '0' COMMENT '租赁点服务员评分1-5分',
`return_point_uid` bigint(20) unsigned DEFAULT '0' COMMENT '归还租赁点uid',
`return_point_score` tinyint(1) unsigned DEFAULT '0' COMMENT '归还点拼分1-5分',
`return_point_server_uid` bigint(20) unsigned DEFAULT '0' COMMENT '归还点 服务员uid',
`return_point_server_score` tinyint(1) unsigned DEFAULT '0' COMMENT '归还点服务员评分',
`device_score` tinyint(1) unsigned DEFAULT '0' COMMENT '设备评分',
`device_id` int(11) unsigned DEFAULT '0' COMMENT '设备id',
`remark` varchar(10000) DEFAULT '' COMMENT '备注',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='评论表';
-- ----------------------------
-- Table structure for oxygen_compensate
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_compensate`;
CREATE TABLE `oxygen_compensate` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`product_id` int(11) unsigned DEFAULT '0' COMMENT '产品id',
`position` varchar(64) NOT NULL DEFAULT '' COMMENT '赔偿部位',
`price` float(10,2) unsigned DEFAULT '0.00' COMMENT '价格',
`sort` int(11) unsigned DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='赔偿表';
-- ----------------------------
-- Table structure for oxygen_device
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_device`;
CREATE TABLE `oxygen_device` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sn` varchar(11) DEFAULT '' COMMENT 'sn',
`bind_uid` int(11) unsigned DEFAULT '0' COMMENT '绑定uid',
`bind_time` datetime DEFAULT NULL COMMENT '绑定时间',
`status` enum('激活','已绑定','租赁中','异常','丢失') DEFAULT '激活' COMMENT '状态',
`create_time` datetime DEFAULT NULL COMMENT '激活时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设备表';
-- ----------------------------
-- Table structure for oxygen_exchange
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_exchange`;
CREATE TABLE `oxygen_exchange` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`order_id` int(11) unsigned DEFAULT '0' COMMENT '订单id',
`from_device_id` int(11) unsigned DEFAULT '0' COMMENT '来源设备id',
`to_device_id` int(11) unsigned DEFAULT '0' COMMENT '更换设备id',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='换货单';
-- ----------------------------
-- Table structure for oxygen_leasehold_class
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_leasehold_class`;
CREATE TABLE `oxygen_leasehold_class` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '' COMMENT '32',
`sort` int(11) unsigned DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='租赁点分类';
-- ----------------------------
-- Table structure for oxygen_leasehold_level
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_leasehold_level`;
CREATE TABLE `oxygen_leasehold_level` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '' COMMENT '名称',
`rate` float(4,3) unsigned NOT NULL DEFAULT '0.050' COMMENT '提成比例',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='租赁点级别';
-- ----------------------------
-- Table structure for oxygen_message
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_message`;
CREATE TABLE `oxygen_message` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(11) unsigned DEFAULT '0' COMMENT '收到人uid',
`content` text COMMENT '内容',
`create_time` datetime DEFAULT NULL COMMENT '新增时间',
`type` enum('业务员','租赁点','服务员','公众号') DEFAULT '业务员' COMMENT '类型',
`status` enum('未读','已读','已删除') DEFAULT '未读' COMMENT '状态',
`read_time` datetime DEFAULT NULL COMMENT '阅读时间',
`data_type` varchar(0) DEFAULT '' COMMENT '数据类型',
`data_id` int(11) unsigned DEFAULT '0' COMMENT '关联id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='消息表';
-- ----------------------------
-- Table structure for oxygen_order
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_order`;
CREATE TABLE `oxygen_order` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`no` char(14) NOT NULL DEFAULT '' COMMENT '订单编号',
`uid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`type` enum('普通单','换货单','续租单') NOT NULL DEFAULT '普通单' COMMENT '类型',
`relate_id` int(11) unsigned DEFAULT '0' COMMENT '关联id',
`remark` varchar(1000) DEFAULT '' COMMENT '备注',
`status` enum('未支付','租赁中','已结束') DEFAULT '未支付' COMMENT '状态',
`finish_time` datetime DEFAULT NULL COMMENT '结束时间',
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
`pay_status` enum('未支付','已支付') DEFAULT '未支付' COMMENT '支付状态',
`activity_id` int(11) unsigned DEFAULT '0' COMMENT '活动id',
`activity_name` varchar(64) DEFAULT '' COMMENT '活动名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';
-- ----------------------------
-- Table structure for oxygen_order_blank
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_order_blank`;
CREATE TABLE `oxygen_order_blank` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`no` char(14) NOT NULL DEFAULT '' COMMENT '单号',
`create_time` datetime DEFAULT NULL COMMENT '申请时间',
`creator_uid` bigint(20) unsigned DEFAULT '0' COMMENT '创建者uid',
`check_time` datetime DEFAULT NULL COMMENT '审核时间',
`name` varchar(64) DEFAULT '' COMMENT '网点名称',
`stock_time` datetime DEFAULT NULL COMMENT '入库时间',
`deliver_address` varchar(128) DEFAULT '' COMMENT '配货地址',
`status` enum('待审核','配货中','已入库') DEFAULT '待审核',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='配货单';
-- ----------------------------
-- Table structure for oxygen_order_blank_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_order_blank_detail`;
CREATE TABLE `oxygen_order_blank_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`order_blank_id` int(11) unsigned DEFAULT '0' COMMENT '配货单id',
`name` varchar(11) NOT NULL DEFAULT '' COMMENT '项目名称',
`amount` int(11) unsigned DEFAULT '0' COMMENT '数量',
`unit` varchar(16) DEFAULT '' COMMENT '单位',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='配货单明细';
-- ----------------------------
-- Table structure for oxygen_order_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_order_detail`;
CREATE TABLE `oxygen_order_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '产品名称',
`price` float(10,2) unsigned DEFAULT '0.00' COMMENT '价格',
`amount` int(11) unsigned DEFAULT '1' COMMENT '数量',
`total` float(10,2) unsigned DEFAULT '0.00' COMMENT '总价',
`sn` varchar(32) DEFAULT '' COMMENT '序列号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单明细';
-- ----------------------------
-- Table structure for oxygen_product
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_product`;
CREATE TABLE `oxygen_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` enum('产品','配件') DEFAULT '产品' COMMENT '类型',
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '名称',
`unit` varchar(16) DEFAULT '' COMMENT '单位',
`mode` enum('出租','销售') DEFAULT '出租' COMMENT '租售模式',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='产品表';
-- ----------------------------
-- Table structure for oxygen_repaire_list
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_repaire_list`;
CREATE TABLE `oxygen_repaire_list` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`no` char(14) NOT NULL DEFAULT '' COMMENT '单号',
`create_time` datetime DEFAULT NULL COMMENT '申请时间',
`uid` int(11) unsigned DEFAULT '0' COMMENT '网点uid',
`deliver_address` varchar(32) DEFAULT '' COMMENT '收货地址',
`check_time` datetime DEFAULT NULL COMMENT '审核时间',
`stock_time` datetime DEFAULT NULL COMMENT '入库时间',
`name` varchar(64) DEFAULT '' COMMENT '网点名称',
`status` enum('待审核','取货中','已取货') DEFAULT '待审核' COMMENT '状态',
`check_uid` int(11) unsigned DEFAULT '0' COMMENT '审核人uid',
`stock_uid` int(11) unsigned DEFAULT '0' COMMENT '入库uid',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报修单';
-- ----------------------------
-- Table structure for oxygen_repaire_list_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_repaire_list_detail`;
CREATE TABLE `oxygen_repaire_list_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`oxygen_repaire_list_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '报修单id',
`name` varchar(32) DEFAULT '' COMMENT '商品名称',
`amount` int(11) unsigned DEFAULT '0' COMMENT '数据',
`unit` varchar(16) DEFAULT '' COMMENT '单位',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报修单明细';
-- ----------------------------
-- Table structure for oxygen_report_lose
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_report_lose`;
CREATE TABLE `oxygen_report_lose` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`no` char(24) NOT NULL DEFAULT '' COMMENT '单号',
`create_time` datetime DEFAULT NULL COMMENT '申请时间',
`uid` int(11) unsigned DEFAULT '0' COMMENT '创建uid',
`deliver_address` varchar(128) DEFAULT '' COMMENT '收货地址',
`check_time` datetime DEFAULT NULL COMMENT '审核时间',
`stock_time` datetime DEFAULT NULL COMMENT '入库时间',
`name` varchar(0) DEFAULT '' COMMENT '网点名称',
`status` enum('配货中','待审核','已入库') DEFAULT '待审核' COMMENT '状态',
`money` float(10,2) unsigned DEFAULT '0.00' COMMENT '应赔金额',
`money_left` float(10,2) unsigned DEFAULT '0.00' COMMENT '剩余赔付状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报损单';
-- ----------------------------
-- Table structure for oxygen_report_lose_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_report_lose_detail`;
CREATE TABLE `oxygen_report_lose_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`repaire_lose_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '报损单id',
`name` varchar(32) DEFAULT '' COMMENT '产品名称',
`amount` int(11) unsigned DEFAULT '0' COMMENT '数量',
`unit` varchar(16) DEFAULT '' COMMENT '单位',
`price` float(10,2) unsigned DEFAULT '0.00' COMMENT '金额',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报损单明细';
-- ----------------------------
-- Table structure for oxygen_return
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_return`;
CREATE TABLE `oxygen_return` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`no` char(14) DEFAULT '' COMMENT '编号',
`create_time` datetime DEFAULT NULL COMMENT '申请时间',
`uid` int(11) unsigned DEFAULT '0' COMMENT '网点uid',
`name` varchar(64) DEFAULT '' COMMENT '网点名称',
`deliver_address` varchar(128) DEFAULT '' COMMENT '收货地址',
`check_time` datetime DEFAULT NULL COMMENT '审核时间',
`stock_time` datetime DEFAULT NULL COMMENT '入库时间',
`status` enum('待审核','配货中','已退货') DEFAULT '待审核',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='退货单';
-- ----------------------------
-- Table structure for oxygen_return_detail
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_return_detail`;
CREATE TABLE `oxygen_return_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`oxygen_return_id` int(11) unsigned DEFAULT '0',
`name` varchar(64) DEFAULT '' COMMENT '名称',
`amount` int(10) unsigned DEFAULT '0' COMMENT '数量',
`unit` varchar(16) DEFAULT '' COMMENT '单位',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='退货单明细';
-- ----------------------------
-- Table structure for oxygen_user_extra
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_user_extra`;
CREATE TABLE `oxygen_user_extra` (
`uid` bigint(20) unsigned NOT NULL,
`creator_uid` int(11) unsigned DEFAULT '0' COMMENT '创建者uid',
`info` json DEFAULT NULL COMMENT '扩展信息',
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户扩展信息表';
-- ----------------------------
-- Table structure for oxygen_wxuser
-- ----------------------------
DROP TABLE IF EXISTS `oxygen_wxuser`;
CREATE TABLE `oxygen_wxuser` (
`uid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
`appid` varchar(32) CHARACTER SET utf8 NOT NULL COMMENT '微信appid',
`session_key` varchar(24) CHARACTER SET utf8 DEFAULT '' COMMENT 'session_key',
`unionid` varchar(64) CHARACTER SET utf8 DEFAULT '' COMMENT '开放平台openid',
`type` enum('小程序','公众号') CHARACTER SET utf8 DEFAULT '小程序' COMMENT '类型',
`nickname` varchar(64) DEFAULT '' COMMENT '昵称',
`sex` enum('男','女','未知') CHARACTER SET utf8 NOT NULL DEFAULT '未知' COMMENT '性别',
`language` varchar(16) DEFAULT '' COMMENT '语言',
`province` varchar(32) CHARACTER SET utf8 DEFAULT '' COMMENT '省',
`city` varchar(32) CHARACTER SET utf8 DEFAULT '' COMMENT '市',
`country` varchar(32) CHARACTER SET utf8 DEFAULT '' COMMENT '国家',
`headimgurl` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '头像',
`lease_times` int(11) unsigned DEFAULT '0' COMMENT '租赁次数',
`lease_time` int(11) unsigned DEFAULT '0' COMMENT '租赁时长',
`lease_money` float(10,2) unsigned DEFAULT '0.00' COMMENT '租赁金额',
`lease_last_order_time` datetime DEFAULT NULL COMMENT '最后租赁时间',
`lease_last_order_return_time` datetime DEFAULT NULL COMMENT '最后归还时间',
`lease_last_order_money` float(10,2) unsigned DEFAULT '0.00' COMMENT '最后租赁金额',
PRIMARY KEY (`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信用户表';
~~~
| 设备 | 数量 |单位|
| --- | --- | --- |
|便携式制氧机套装|100|套|
|充电宝|20|只|
|鼻氧管|200|根|
## inotify 的安装
一、安装
1) 从内核和目录里面查看是否支持inotify
[root@nfs01 ~]# **uname -r**
**2.6.32-573.el6.x86_64**
[root@nfs01 ~]#** ls -l /proc/sys/fs/inotify/** -→主要查看下面有没有三个目录
总用量 0
-rw-r--r-- 1 root root 0 1月 21 13:03 max_queued_events
-rw-r--r-- 1 root root 0 1月 21 13:03 max_user_instances
-rw-r--r-- 1 root root 0 1月 21 13:03 max_user_watches
**2****)检查是否有安装inotify ****如果没有就安装**
**rpm -qa inotify-tools**
没有就先安装epol源
yum.repos.d]# **wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo**
之后安装
[root@nfs01 ~]#** yum install inotify-tools -y**
**二、参数讲解、**
[root@nfs01 ~]# **which inotifywait**
**/usr/bin/inotifywait**
[root@nfsserver inotify-tools]# **bin/inotifywait —help**
r :递归查询目录
q:打印很少的信息,仅仅打印监控事件的信息 安静状态
m:始终保持事件监听状态
excluder#排除文件或者目录的时候不区分大小写
timefmt:指定时间输出的格式
d :后台运行
-e: 事件 里面有很多方法
下面是事件参数
Events:
access file or directory contents were read 访问
modify file or directory contents were written 修改
attrib file or directory attributes changed 属性发生变化
close_write file or directory closed, after being opened in 写入之后关闭
writeable mode
close_nowrite file or directory closed, after being opened in read-only mode
close file or directory closed, regardless of read/write mode
open file or directory opened
moved_to file or directory moved to watched directory 移动到哪里
moved_from file or directory moved from watched directory
move file or directory moved to or from watched directory
create file or directory created within watched directory
delete file or directory deleted within watched directory
delete_self file or directory was deleted
unmount file system containing file or directory unmounted卸载
之后就可以和nfs共享服务器之间的实时备份
## 百度图片识别
~~~
function ocr_code($url, $length = 4, $debug =0){
$img = file_get_contents($url);
$tmp = tempnam(sys_get_temp_dir(), 'code');
file_put_contents($tmp, $img);
$ret = plugin_action('BaiduAi', 'Ocr', 'basicAccurate', [$img]);
$words = $ret['words_result'][0]['words'];
$words = trim($words, ' ');
$words = str_ireplace(['.',' ', '\''], '', $words);
if($debug){
echo '<img src="'.base64EncodeImage($tmp).'">';
dump($ret);
dump($words);
}
return strlen($words)== $length? $words: '';
}
~~~
## 身份证识别
`composer require "douyasi/identity-card:~2.0"`
`$ID = new Douyasi\IdentityCard\ID();`
`$passed = $ID->validateIDCard('42032319930606629x');`
## 获取某网站cookie
```
public function get_cookie(){
// @unlink('verify.png');
// @unlink('result.png');
$puppeteer = new Puppeteer([
'executable_path'=>'/usr/local/bin/node',
]);
$browser = $puppeteer->launch([
'args'=>['--no-sandbox', '--disable-setuid-sandbox']
]);
$domain = is_online()? 'fj.pizhigu.com':'test.pizhigu.com';
// $domain = 'fj.pizhigu.com';
$url = url('/',[], false, $domain).'uploads/verify.png';
$ocr_url = url('/index/service/ocr_code', [], false, $domain);
$debug_url = url('/dingding/index/front_log', [], false, $domain);
try {
$page = $browser->newPage();
$page->goto('http://cpservice.sipo.gov.cn/index.jsp');
$img = $page->querySelector("#Verify");
$usernameInput = $page->querySelector("#username");
$usernameInput->focus(); //定位到用户名
$page->keyboard->type("91321102338928957N");
$passwordInput = $page->querySelector("#password");
$passwordInput->focus();
$pwd = config('cps_pwd');
$page->keyboard->type($pwd);
// $page->screenshot(['path' => 'uploads/result0.png']);
$page->screenshot(['path' => 'uploads/verify.png',
'clip'=>[
'x'=>616,'y'=>546, 'width'=>70,'height'=>30
]
]);
$js = <<<JS
var xmlhttp;
var ret = '1111';
if (window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST","{$ocr_url}",false);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url={$url}");
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
ret = xmlhttp.responseText;
return;
}
}
if (xmlhttp.readyState==4 && xmlhttp.status==200){
ret = xmlhttp.responseText;
}else{
xmlhttp.open("GET","{$debug_url}?msg="+ JSON.stringify([xmlhttp.readyState, xmlhttp.status,xmlhttp.responseText, xmlhttp.responseXML]),true);
xmlhttp.send();
}
return ret;
JS;
$verifyFunction = JsFunction::createWithBody($js);
$dimensions = $page->evaluate($verifyFunction);
// dump($dimensions);
if($dimensions != '1111' && $dimensions != ''){
$securityCodeInput = $page->querySelector("#securityCode");
$securityCodeInput->focus();
$page->keyboard->type($dimensions);
$page->screenshot(['path' => 'uploads/result.png']);
$loginFunction = JsFunction::createWithBody("
return login();
");
$dimensions2 = $page->evaluate($loginFunction);
$page->waitForNavigation(['timeout'=>10000]);
$js = <<<JS
var str = document.cookie;
str += "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
document.cookie = str;
return document.cookie;
JS;
$jumpFunction = JsFunction::createWithBody($js);
$dimensions3 = $page->evaluate($jumpFunction);
$page->screenshot(['path' => 'uploads/result2.png']);
dump($dimensions3);
if($dimensions3){
$data = [
'name' => self::$cpservice_cache,
'value' => $dimensions3,
];
Db::name('service_config')->insertAll([$data], true);
$msg = '登录成功,获得cookie:'.$dimensions3;
}else{
$msg = '登录失败码失败';
$this->refresh_cookie();
}
}else{
$msg = '识别验证码失败';
$this->refresh_cookie();
}
// ptrace($msg);
trace($msg);
} catch (Node\Exception $exception) {
// ptrace($e->getMessage().PHP_EOL.$e->getTraceAsString());
trace($e->getMessage().PHP_EOL.$e->getTraceAsString());
}
$browser->close();
}
```
## tcp
# tp5_swoole_demo
thinkphp5 swoole 演示demo
# swoole安装
## wsl
去windows应用商店里搜索ubutun 安装18.64
然后通过oneinstalk 安装php环境 只是演示的话可以不装 nginx和数据库
```wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --php_option 8 --php_extensions swoole --reboot ```
因为不是root用户 拆成两句执行 ```sudo wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz```
然后执行 sudo ./oneinstack/install.sh --php_option 8 --php_extensions swoole --reboot
> 安装失败
## apt-get
sudo apt-get install php7.0
> 安装失败
## lnmp
wget http://soft.vpser.net/lnmp/lnmp1.5.tar.gz -cO lnmp1.5.tar.gz && tar zxf lnmp1.5.tar.gz && cd lnmp1.5 && ./install.sh lnmp
### 验证
php -m 看到swoole扩展即可
# 初始化tp项目
# 安装think-swoole扩展
在wsl 对应目录里(cd /mnt/d/wamp64/www/git/tp5_swoole_demo/) 运行
composer require topthink/think-swoole
> 切换到wsl 目录访问模式下安装,不然提示扩展未安装
> sudo pecl install swoole
# ptrace
array:5 [▼
"chatid" => "chat13280cb4120b6aae2d94fad60bf4a289"
"openConversationId" => "cidK2gTCMAZZxg2PxFEm145gw=="
"conversationTag" => 2
"errmsg" => "ok"
"errcode" => 0
]
# tcp 的实现
## 类
'swoole_class' => 'app\http\Swoole' 指定一个类
所有的其他配置放在类的 options里
## 特殊配置
'pid_file'=>'swoole_pid',
'log_file'=>'swoole.log',
pid_file 最好设置一下
然后log_file 也指定一下 方便调试
## 调试阶段
daemonize => false
然后就不会记录日志 ,直接显示在屏上。 开启,则会记录在日志里。
如果程序出错, 会记录到 runtime 日期_cli.log里
最后指定 'exception_handle' => 'app\common\lib\Handle',
好统一报错到你指定的频道 如我的例子是钉钉。
## 工具
tcp/udp socket 调试工具。
## inotify reload 扩展
https://github.com/yangweijie/note/issues/59
# 疑惑
看了think\swoole 的源码 发现http 服务里 有一个自带的 monitor
感觉tcp 里配了也不起作用。
官方的pid_file 获取好像有bug, 按照官方的设置的server php think swoole:server
start 后 stop | reload 都不会精确判断。
如果想 正确控制 启动 和监控文件变化 ,请参考 [如何用thinkphp5.1和vue 开发一个小游戏] (https://www.kancloud.cn/book/yangweijie/how_to_develop_one_game_with_tp5_1_vue/dashboard)
里的 类里自己自定义 构造方法 后 手动判断是否启动后 执行init 方法。
## 效果图
![](https://box.kancloud.cn/e86fd96c6efee051479e8a3fda88ec61_757x72.png)
![](https://box.kancloud.cn/7847b1c9c84172ec14a14040fc369290_698x155.png)
![](https://box.kancloud.cn/3415f65ee7caa56592d5d42b78605362_910x553.png)
![](https://box.kancloud.cn/271d5ea76175965626ac4e8cd1f3de4e_1286x223.png)
# 中文路径 特殊符号给前端下载的问题
后端生成的中文名附件 给前端 base64encode 一下
然后接受的传后端 path 参数 去下载 结果报 is_file not a valid path
对比发现 url 上 是+ 到php获取时变空格了
`$path = str_ireplace(' ', '+', $path); ` 替换后 就能正常解析了
# tp6 里 跨域中间件和jwt冲突的问题
jwt包默认需要header头里传一个http-x-token 的key
开启跨域包后 被重置 了,
以前不知道如何给默认中间件传变量,经过阅读源码时发现了
/**
* 加载全局中间件
*/
protected function loadMiddleware(): void
{
if (is_file($this->app->getBasePath() . 'middleware.php')) {
$this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
}
}
会将应用目录下的middleware 数组传入,
/**
* 导入中间件
* @access public
* @param array $middlewares
* @param string $type 中间件类型
* @return void
*/
public function import(array $middlewares = [], string $type = 'global'): void
{
foreach ($middlewares as $middleware) {
$this->add($middleware, $type);
}
}
/**
* 注册中间件
* @access public
* @param mixed $middleware
* @param string $type 中间件类型
* @return void
*/
public function add($middleware, string $type = 'global'): void
{
$middleware = $this->buildMiddleware($middleware, $type);
if (!empty($middleware)) {
$this->queue[$type][] = $middleware;
$this->queue[$type] = array_unique($this->queue[$type], SORT_REGULAR);
}
}
/**
* 解析中间件
* @access protected
* @param mixed $middleware
* @param string $type 中间件类型
* @return array
*/
protected function buildMiddleware($middleware, string $type): array
{
if (is_array($middleware)) {
[$middleware, $params] = $middleware;
}
if ($middleware instanceof Closure) {
return [$middleware, $params ?? []];
}
if (!is_string($middleware)) {
throw new InvalidArgumentException('The middleware is invalid');
}
//中间件别名检查
$alias = $this->app->config->get('middleware.alias', []);
if (isset($alias[$middleware])) {
$middleware = $alias[$middleware];
}
if (is_array($middleware)) {
$this->import($middleware, $type);
return [];
}
return [[$middleware, 'handle'], $params ?? []];
}
如果是闭包直接执行,如果非闭包就会走中间件的handle方法
经过我的实验
~~~
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// \think\middleware\SessionInit::class
[
\think\middleware\AllowCrossDomain::class, [
[
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,http-x-token,1234'
]
]
],
];
~~~
这么配置 是可以覆盖 AllowCrossDomain handle方法的第三个参数的, 记得你开启的全局类名 和参数放在一个数组里,参数本身里也是个数组 每个值是后面可变参数的展开
/**
* 允许跨域请求
* @access public
* @param Request $request
* @param Closure $next
* @param array $header
* @return Response
*/
public function handle($request, Closure $next, ?array $header = [])
{
**格式字串可以识别以下`format`参数的字符串**
| `format`字符 | 说明 | 返回值例子 |
| --- | --- | --- |
| *日* | \--- | \--- |
| *d* | 月份中的第几天,有前导零的 2 位数字 | *01*到*31* |
| *D* | 星期中的第几天,文本表示,3 个字母 | *Mon*到*Sun* |
| *j* | 月份中的第几天,没有前导零 | *1*到*31* |
| *l*("L"的小写字母) | 星期几,完整的文本格式 | *Sunday*到*Saturday* |
| *N* | ISO-8601 格式数字表示的星期中的第几天(PHP 5.1.0 新加) | *1*(表示星期一)到*7*(表示星期天) |
| *S* | 每月天数后面的英文后缀,2 个字符 | *st*,*nd*,*rd* 或者*th*。可以和*j*一起用 |
| *w* | 星期中的第几天,数字表示 | *0*(表示星期天)到*6*(表示星期六) |
| *z* | 年份中的第几天 | *0*到*365* |
| *星期* | \--- | \--- |
| *W* | ISO-8601 格式年份中的第几周,每周从星期一开始(PHP 4.1.0 新加的) | 例如:*42*(当年的第 42 周) |
| *月* | \--- | \--- |
| *F* | 月份,完整的文本格式,例如 January 或者 March | *January*到*December* |
| *m* | 数字表示的月份,有前导零 | *01*到*12* |
| *M* | 三个字母缩写表示的月份 | *Jan*到*Dec* |
| *n* | 数字表示的月份,没有前导零 | *1*到*12* |
| *t* | 给定月份所应有的天数 | *28*到*31* |
| *年* | \--- | \--- |
| *L* | 是否为闰年 | 如果是闰年为*1*,否则为*0* |
| *o* | ISO-8601 格式年份数字。这和 *Y*的值相同,只除了如果 ISO 的星期数(*W*)属于前一年或下一年,则用那一年。(PHP 5.1.0 新加) | Examples:*1999*or*2003* |
| *Y* | 4 位数字完整表示的年份 | 例如:*1999*或*2003* |
| *y* | 2 位数字表示的年份 | 例如:*99*或*03* |
| *时间* | \--- | \--- |
| *a* | 小写的上午和下午值 | *am*或*pm* |
| *A* | 大写的上午和下午值 | *AM*或*PM* |
| *B* | Swatch Internet 标准时 | *000*到*999* |
| *g* | 小时,12 小时格式,没有前导零 | *1*到*12* |
| *G* | 小时,24 小时格式,没有前导零 | *0*到*23* |
| *h* | 小时,12 小时格式,有前导零 | *01*到*12* |
| *H* | 小时,24 小时格式,有前导零 | *00*到*23* |
| *i* | 有前导零的分钟数 | *00*到*59*\> |
| *s* | 秒数,有前导零 | *00*到*59*\> |
| *u* | 毫秒 (PHP 5.2.2 新加)。需要注意的是 **date()**函数总是返回 *000000*因为它只接受integer 参数, 而DateTime::format()才支持毫秒。 | 示例:*654321* |
| *时区* | \--- | \--- |
| *e* | 时区标识(PHP 5.1.0 新加) | 例如:*UTC*,*GMT*,*Atlantic/Azores* |
| *I* | 是否为夏令时 | 如果是夏令时为*1*,否则为*0* |
| *O* | 与格林威治时间相差的小时数 | 例如:*+0200* |
| *P* | 与格林威治时间(GMT)的差别,小时和分钟之间有冒号分隔(PHP 5.1.3 新加) | 例如:*+02:00* |
| *T* | 本机所在的时区 | 例如:*EST*,*MDT*(【译者注】在 Windows 下为完整文本格式,例如"Eastern Standard Time",中文版会显示"中国标准时间")。 |
| *Z* | 时差偏移量的秒数。UTC 西边的时区偏移量总是负的,UTC 东边的时区偏移量总是正的。 | *\-43200*到*43200* |
| *完整的日期/时间* | \--- | \--- |
| *c* | ISO 8601 格式的日期(PHP 5 新加) | 2004-02-12T15:19:21+00:00 |
| *r* | RFC 822 格式的日期 | 例如:*Thu, 21 Dec 2000 16:01:07 +0200* |
| *U* | 从 Unix 纪元(January 1 1970 00:00:00 GMT)开始至今的秒数 | 参见time() |