navicat 无法设置decimal默认值的问题

https://www.zhangshuxian.top/article/102

SELECT
        CONCAT("ALTER TABLE ",TABLE_NAME," MODIFY COLUMN ",COLUMN_NAME," ",COLUMN_TYPE,(case when IS_NULLABLE = "NO" THEN " NOT NULL" ELSE "" END)," DEFAULT 0 COMMENT '",COLUMN_COMMENT,"';") AS 'sql',
    TABLE_SCHEMA AS '库名',
    TABLE_NAME AS '表名',
    COLUMN_NAME AS '列名',
    ORDINAL_POSITION AS '列的排列顺序',
    COLUMN_DEFAULT AS '默认值',
    IS_NULLABLE AS '是否为空',
    DATA_TYPE AS '数据类型',
    CHARACTER_MAXIMUM_LENGTH AS '字符最大长度',
    NUMERIC_PRECISION AS '数值精度(最大位数)',
    NUMERIC_SCALE AS '小数精度',
    COLUMN_TYPE AS '列类型',
    COLUMN_KEY 'KEY',
    EXTRA AS '额外说明',
    COLUMN_COMMENT AS '注释'
FROM
    information_schema.`COLUMNS`
WHERE
    TABLE_SCHEMA = 'zxcrm-demo'
    AND DATA_TYPE = 'decimal'
    AND COLUMN_DEFAULT IS NULL and IS_NULLABLE = "NO";

常见网络摄像机的端口及RTSP地址

来源:https://www.jiangyu.org/port-and-rtsp-address-of-several-ipcams/

备份一下

海康威视
默认IP地址:192.168.1.64/DHCP 用户名admin 密码自己设
端口:“HTTP 端口”(默认为 80)、“RTSP 端口”(默认为 554)、“HTTPS 端 口”(默认 443)和“服务端口”(默认 8000),ONVIF端口 80。
RTSP地址:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
说明:
username: 用户名。例如admin。
password: 密码。例如12345。
ip: 为设备IP。例如 192.0.0.64。
port: 端口号默认为554,若为默认可不填写。
codec:有h264、MPEG-4、mpeg4这几种。
channel: 通道号,起始为1。例如通道1,则为ch1。
subtype: 码流类型,主码流为main,辅码流为sub。
例如,请求海康摄像机通道1的主码流,Url如下
主码流:
rtsp://admin:12345@192.0.0.64:554/h264/ch1/main/av_stream
子码流:
rtsp://admin:12345@192.0.0.64/mpeg4/ch1/sub/av_stream

大华
默认IP地址:192.168.1.108 用户名/密码:admin/admin
端口:TCP 端口 37777/UDP 端口 37778/http 端口 80/RTSP 端口号默认为 554/HTTPs 443/ONVIF 功能默认为关闭,端口80
RTSP地址:rtsp://username:password@ip:port/cam/realmonitor?channel=1&subtype=0
说明:
username: 用户名。例如admin。
password: 密码。例如admin。
ip: 为设备IP。例如 10.7.8.122。
port: 端口号默认为554,若为默认可不填写。
channel: 通道号,起始为1。例如通道2,则为channel=2。
subtype: 码流类型,主码流为0(即subtype=0),辅码流为1(即subtype=1)。
例如,请求某设备的通道2的辅码流,Url如下
rtsp://admin:admin@10.12.4.84:554/cam/realmonitor?channel=2&subtype=1

雄迈/巨峰
默认IP地址:192.168.1.10 用户名admin 密码空
端口:TCP端口:34567 和 HTTP端口:80,onvif端口是8899
RTSP地址:rtsp://10.6.3.57:554/user=admin&password=&channel=1&stream=0.sdp?
10.6.3.57这个是被连接的设备的IP
554这个是RTSP服务的端口号,可以在设备的网络服务里面更改
user=admin这个是设备的登录用户名
password= 密码空
channel=1 第一通道
stream=0.sdp?主码流
stream=1.sdp?副码流
图片抓拍地址:http://ip/webcapture.jpg?command=snap&channel=1

天视通
默认IP地址:192.168.0.123 用户名admin 密码123456
端口:http端口80 数据端口8091 RTSP端口554 ONVIF端口 80
RTSP地址:主码流地址:rtsp://192.168.0.123:554/mpeg4
子码流地址:rtsp://192.168.0.123:554/mpeg4cif
需要入密码的地址: 主码流 rtsp://admin:123456@192.168.0.123:554/mpeg4
子码流 rtsp://admin:123456@192.168.0.123:554/mpeg4cif
图片抓拍地址:http://ip/snapshot.cgi

中维/尚维
默认IP地址:DHCP 默认用户名admin 默认密码 空
RTSP地址:rtsp://0.0.0.0:8554/live1.264(次码流)
rtsp://0.0.0.0:8554/live0.264 (主码流)

九安
RTSP地址:rtsp://IP:port(website port)/ch0_0.264(主码流)
rtsp://IP:port(website port)/ch0_1.264(子码流)

技威/YOOSEE
默认IP地址:DHCP 用户名admin 密码123
RTSP地址:主码流:rtsp://IPadr:554/onvif1
次码流:rtsp://IPadr:554/onvif2
onvif端口是5000
设备发现的端口是3702

V380
默认IP地址:DHCP 用户名admin 密码空/admin
onvif端口8899
RTSP地址:主码流rtsp://ip//live/ch00_1
子码流rtsp://ip//live/ch00_0

宇视
默认IP地址: 192.168.0.13/DHCP 默认用户名 admin 和默认密码 123456
端口:HTTP 80/RTSP 554/HTTPS 110(443)/onvif端口 80
RTSP地址:rtsp://用户名:密码@ip:端口号/video123 123对应3个码流

天地伟业
默认IP地址:192.168.1.2 用户名“Admin”、密码“1111”
onvif端口号“8080”
RTSP地址:rtsp://192.168.1.2

巨龙/JVT
默认IP地址:192.168.1.88 默认用户名 admin 默认密码admin
RTSP地址:
主码流地址:rtsp://IP地址/av0_0
次码流地址:rtsp://IP地址/av0_1
onvif端口 2000
图片抓拍地址:http://ip/capture/webCapture.jpg?channel=1&FTpsend=0&checkinfo=0
(http://ip/cgi-bin/images_cgi?channel=1&user=admin&pwd=admin)

php ubuntu 多版本安装

php 多版本安装 from ppa

https://launchpad.net/~ondrej/+archive/ubuntu/php

sudo add-apt-repository ppa:ondrej/php
sudo apt update

然后就可以用sudo apt isntall php-7.4这种方式安装对应版本php

扩展可以直接用apt install php-7.4-redis这种方式安装

不确定的扩展名可以用apt search php-版本-redis搜索包名

  • 多版本切换

如果需要多版本切换,可以使用ubuntu 的update-alternatives实现

用上面ppa的包安装的php都会作为php的候选项,比如使用命令

update-alternatives --list php
/usr/bin/php7.4
/usr/bin/php8.2

需要切换php命令的版本可以使用

update-alternatives --config php
 2 个候选项可用于替换 php (提供 /usr/bin/php)。

  选择       路径           优先级  状态
------------------------------------------------------------
* 0            /usr/bin/php8.2   82        自动模式
  1            /usr/bin/php7.4   74        手动模式
  2            /usr/bin/php8.2   82        手动模式

如果有应用不是使用apt安装的,可以使用下面的命令添加到候选项目

# 链接  名称  (实际)路径   优先级
sudo update-alternatives --install /usr/bin/vim vim /usr/bin/vim.nox 40

  • php-fpm 多版本

如果fpm也需要多版本,可以先apt安装多版本的fpm

使用systemctl start php7.4-fpm 启动对应版本的php-fpm

查看目录/etc/php/7.4/fpm/pool.d/www.conf

 listen = /run/php/php7.4-fpm.sock  //可以看到监听地址

nginx设置php文件的fastcgi=/run/php/php7.4-fpm.sock

需要切换php-fpm版本就找到对应配置的fpm监听地址,修改nginx对应网站的转发配置

PHP 对html文件进行处理

有一批静态文件需要删除一些元素,考虑使用php脚本批量处理

step1 扫描目录

use Masterminds\HTML5;
$dir = __DIR__ . '/path/to/html';
$fileNames = scandir($dir);
$html5 = new HTML5(['disable_html_ns'=> true]);

foreach ($fileNames as $fileName) {
    if (in_array($fileName, ['.', '..'])) {
        continue;
    }
    $filePath = $dir . '/' . $fileName;
    if (!is_file($filePath)) {
        continue;
    }
}

这里使用Masterminds\HTML5这个包,直接使用DOMdocument读取h5会出现问题

step2 加载文件

$document = $html5->loadHTMLFile($filePath);
$xpath = new DOMXPath($document);

step3 修改节点

clearNodes($xpath);

function clearNodes($xpath) {
    clearElements($xpath, '//div[@class="panel panel-default tab-content"]');
}

step4 保存文件

$html5->save($document, $filePath);

微信模板消息改版后发送规则

改版后发送的字段需要跟小程序订阅消息一样遵守字段规则,文档还没更新,这里记录一下,如果不按规则发送会提示参数有问题。

订阅消息参数值内容限制说明

参数类别参数说明参数值限制说明
thing.DATA事物20个以内字符可汉字、数字、字母或符号组合
number.DATA数字32位以内数字只能数字,可带小数
letter.DATA字母32位以内字母只能字母
symbol.DATA符号5位以内符号只能符号
character_string.DATA字符串32位以内数字、字母或符号可数字、字母或符号组合
time.DATA时间24小时制时间格式(支持+年月日),支持填时间段,两个时间点之间用“~”符号连接例如:15:01,或:2019年10月1日 15:01
date.DATA日期年月日格式(支持+24小时制时间),支持填时间段,两个时间点之间用“~”符号连接例如:2019年10月1日,或:2019年10月1日 15:01
amount.DATA金额1个币种符号+10位以内纯数字,可带小数,结尾可带“元”可带小数
phone_number.DATA电话17位以内,数字、符号电话号码,例:+86-0766-66888866
car_number.DATA车牌8位以内,第一位与最后一位可为汉字,其余为字母或数字车牌号码:粤A8Z888挂
name.DATA姓名10个以内纯汉字或20个以内纯字母或符号中文名10个汉字内;纯英文名20个字母内;中文和字母混合按中文名算,10个字内
phrase.DATA汉字5个以内汉字5个以内纯汉字,例如:配送中
enum.DATA枚举值只能上传枚举值范围内的字段值调用接口获取参考枚举值

符号表示除中文、英文、数字外的常见符号,不能带有换行等控制字符。 时间格式支持HH:MM:SS或者HH:MM。 日期包含年月日,为y年m月d日,y年m月、m月d日格式,或者用‘-’、‘/’、‘.’符号连接,如2018-01-01,2018/01/01,2018.01.01,2018-01,01-01。 每个模板参数都会以类型为前缀,例如第一个数字模板参数为number01.DATA,第二个为number02.DATA

wsl 静态ip启动

添加文件

/etc/profile.d/static-ip.sh

ip addr del $(ip addr show eth0 | grep 'inet\b' | awk '{print $2}' | head -n 1) dev eth0
ip addr add 192.168.1.177/24 broadcast 192.168.1.255 dev eth0
ip route add 0.0.0.0/0 via 192.168.1.1 dev eth0

重启后就会按照192.168.1.177这个ip启动了

wsl连接的虚拟网卡使用hyper-v管理器设置为直接连接外部网络

微信支付v3对接

证书解析链接,查看证书序列号 https://myssl.com/cert_decode.html

平台证书获取

php版本工具 https://github.com/wechatpay-apiv3/wechatpay-php

composer 安装后,进入bin目录

执行命令

php CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}

mchSerialNo用上面提供的解析工具解析获得序列号

mchId 商户号

swoole协程通信

之前一直看文档说协程之间通信可以用通道实现,但是都只是说可以用通道推数据和读数据,没有提到怎么同步保存数据

花了很多时间调试修改,实现了一下使用一个数据处理协程对数据进行读写,保存到协程上下文

<?php
use Swoole\Coroutine;

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;



run(function() {
    //写通道,供生产者写入数据
    $channelWrite = new Coroutine\Channel(1);
    //读通道,供消费者读取数据
    $channelRead = new Coroutine\Channel(1);

    //数据处理协程
    go(function () use ($channelWrite, $channelRead) {
        //用这个协程的上下文存储数据
        $pcid =Coroutine::getCid();
        $context = Coroutine::getContext($pcid);
        $context['count'] = [];
        go(function() use ($channelWrite, $pcid) {
            //用父协程id获取上下文,直接传数据数据修改不会同步
            $context = Coroutine::getContext($pcid);
            //从写通道读取数据,放入父协程上下文保存
            while(true) {
                $data = $channelWrite->pop();
                if (!$data) {
                    break;
                }
                $context['count'] = $data;
            }
        });
        go(function() use ($channelRead, $pcid) {
            //用父协程id获取上下文,直接传数据数据修改不会同步
            $context = Coroutine::getContext($pcid);
            //从父协程上下文获取实时数据,传入读通道,供消费协程使用
            while(true) {
                $res = $channelRead->push($context['count']);
                if (!$res) {
                    break;
                }
            }
        });
    });

    // 多个消费者协程和数据生产协程
    go (function() use ($channelRead, $channelWrite) {
        for ($i = 0; $i < 100; $i++) {
            Coroutine::sleep(1);
            if ($i % 2 == 0) {
                $data = $channelRead->pop();
                echo '读数据:', PHP_EOL;
                print_r($data);
            } else {
                $channelWrite->push(array_fill(0, 5, $i));
                echo '写入数据:'.$i, PHP_EOL;
            }
        }
        $channelRead->close();
        $channelWrite->close();
        echo '关闭通道';
    });
});

还需要对读写协程上下文做一个读写锁,应该就可以保证数据一致性

<?php
use Swoole\Coroutine;
use Swoole\Lock;
use Swoole\Timer;

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;



run(function() {
    $channelWrite = new Coroutine\Channel(1);
    $channelRead = new Coroutine\Channel(1);

    //数据处理协程
    go(function () use ($channelWrite, $channelRead) {
        //用这个协程的上下文存储数据
        $pcid =Coroutine::getCid();
        $context = Coroutine::getContext($pcid);
        $context['count'] = 0;

        //读写锁
        $lock = new Lock(SWOOLE_RWLOCK);


        go(function() use ($channelWrite, $pcid, $lock) {
            //用父协程id获取上下文,直接传数据数据不一致
            $context = Coroutine::getContext($pcid);
            //从写通道读取数据,放入父协程上下文保存
            while(true) {
                $data = $channelWrite->pop();
                if (!$data) {
                    break;
                }
                // echo '写入数据(等写锁)', PHP_EOL;
                $lock->lock();
                $context['count'] = $data;
                // echo '写入数据', PHP_EOL;
                $lock->unlock();
            }
        });
        go(function() use ($channelRead, $pcid, $lock) {
            //用父协程id获取上下文,直接传数据数据不一致
            $context = Coroutine::getContext($pcid);
            //从父协程上下文获取实时数据,传入读通道,供消费协程使用
            while(true) {
                // echo '读取数据(等读锁)', PHP_EOL;
                $lock->lock_read();
                $data = $context['count'];
                // echo '读取数据完成', PHP_EOL;
                $lock->unlock();
                $res = $channelRead->push($data);
                if (!$res) {
                    break;
                }
            }
        });
    });

    // 多个消费者协程和数据生产协程
    go (function() use ($channelRead, $channelWrite) {
        Timer::tick(1000, function() use ($channelRead) {
            $data = $channelRead->pop();
            echo date('[i:s]') . '读数据:' . $data, PHP_EOL;
        });
        for ($i = 1; $i < 10; $i++) {
            Coroutine::sleep(1.5);
            $channelWrite->push($i);
            echo date('[i:s]') . '写入数据:'.$i, PHP_EOL;
        }
    });
});

输出

[00:11]读数据:0
[00:11]写入数据:1
[00:12]读数据:0
[00:13]读数据:0
[00:13]写入数据:2
[00:14]读数据:1
[00:14]写入数据:3
[00:15]读数据:1
[00:16]读数据:2
[00:16]写入数据:4
[00:17]读数据:3
[00:17]写入数据:5
[00:18]读数据:3
[00:19]读数据:4
[00:19]写入数据:6
[00:20]读数据:5
[00:20]写入数据:7
[00:21]读数据:5
[00:22]读数据:6
[00:22]写入数据:8
[00:23]读数据:7
[00:23]写入数据:9
[00:24]读数据:7
[00:25]读数据:8
[00:26]读数据:9
[00:27]读数据:9
[00:28]读数据:9
[00:29]读数据:9
[00:30]读数据:9
[00:31]读数据:9
[00:32]读数据:9