mirror of
https://github.com/lkeme/BiliHelper-personal.git
synced 2025-12-19 01:20:08 +08:00
[refactor] all
This commit is contained in:
parent
8a9148726b
commit
95e4f9293e
12
.github/FUNDING.yml
vendored
12
.github/FUNDING.yml
vendored
@ -1,12 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: [ 'https://i.loli.net/2019/07/13/5d2963e5cc1eb22973.png' ]
|
||||
47
.github/ISSUE_TEMPLATE/Issue_Template_CN.md
vendored
47
.github/ISSUE_TEMPLATE/Issue_Template_CN.md
vendored
@ -1,47 +0,0 @@
|
||||
# Issue: BiliHepler 程序问题
|
||||
|
||||
<!-- 上面是标题 下面才是正文 -->
|
||||
|
||||
### 版本、安装方式、系统
|
||||
|
||||
1. 你在使用什么版本的 BiliHelper
|
||||
|
||||
|
||||
2. 你通过什么方式安装 BiliHepler
|
||||
|
||||
|
||||
3. 你所使用的操作系统
|
||||
|
||||
---
|
||||
|
||||
### 描述问题
|
||||
|
||||
<!-- 在下方简要描述问题 -->
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 复现问题的步骤
|
||||
|
||||
<!-- 在下方描述如何复现问题 -->
|
||||
|
||||
|
||||
---
|
||||
|
||||
### BiliHelper 运行日志:
|
||||
|
||||
<!-- 如果条件允许请附日志 -->
|
||||
|
||||
```shell
|
||||
# 此处贴入运行日志
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 截图
|
||||
|
||||
<!-- 如果条件允许请附图 -->
|
||||
|
||||
47
.github/ISSUE_TEMPLATE/Issue_Template_EN.md
vendored
47
.github/ISSUE_TEMPLATE/Issue_Template_EN.md
vendored
@ -1,47 +0,0 @@
|
||||
# Issue: Bug Report
|
||||
|
||||
<!-- 上面是标题 下面才是正文 -->
|
||||
|
||||
### Version, approach of installation, operating system
|
||||
|
||||
1. What version of BiliHelper are you using?
|
||||
|
||||
|
||||
2. What approach of installation do you install BiliHelper?
|
||||
|
||||
|
||||
3. What is your operating system?
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
<!-- Describe your problem below -->
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
<!-- Describe how to reproduce problem below -->
|
||||
|
||||
|
||||
---
|
||||
|
||||
### BiliHelper Logs:
|
||||
|
||||
<!-- Paste log if possible -->
|
||||
|
||||
```shell
|
||||
# Paste running logs here
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Screenshot
|
||||
|
||||
<!-- Paste screenshot if possible -->
|
||||
|
||||
22
.github/workflows/build_image_bhp.yml
vendored
22
.github/workflows/build_image_bhp.yml
vendored
@ -1,22 +0,0 @@
|
||||
name: "BiliHelper-personal Docker Image Buildx Stable Github"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build BiliHelper-personal Docker Image Build Stable Github
|
||||
steps:
|
||||
- name: Checkout master
|
||||
uses: actions/checkout@master
|
||||
- name: Build and publish image
|
||||
uses: ilteoood/docker_buildx@master
|
||||
with:
|
||||
publish: true
|
||||
imageName: lkeme/bilihelper-personal
|
||||
dockerFile: docker/Dockerfile
|
||||
platform: linux/amd64,linux/arm64,linux/arm/v7
|
||||
# platform: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8
|
||||
tag: latest
|
||||
dockerUser: ${{ secrets.DOCKER_USERNAME }}
|
||||
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}
|
||||
31
.gitignore
vendored
31
.gitignore
vendored
@ -5,41 +5,30 @@
|
||||
# IntelliJ project files
|
||||
.idea
|
||||
.idea/
|
||||
index1.php
|
||||
user/
|
||||
record/
|
||||
temp/
|
||||
tmp/
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
/vendor/
|
||||
composer.lock
|
||||
/configs/
|
||||
config
|
||||
/conf/user*.ini
|
||||
*.log
|
||||
Traits/
|
||||
README1.md
|
||||
conf/user.ini
|
||||
conf/user1.ini
|
||||
/conf/user.ini
|
||||
/conf/test.ini
|
||||
/conf/test1.ini
|
||||
/src/backup/
|
||||
script.php
|
||||
|
||||
task/*
|
||||
cache/*
|
||||
log/*
|
||||
script.php
|
||||
test.php
|
||||
index1.php
|
||||
|
||||
# ignore all files in lib/
|
||||
#task/*
|
||||
#cache/*
|
||||
#log/*
|
||||
|
||||
# except for .gitkeep
|
||||
!.gitkeep
|
||||
# ignore TODO file in root directory,not subdir/TODO
|
||||
|
||||
/TODO
|
||||
/Todo
|
||||
/backup
|
||||
/vendor
|
||||
|
||||
# 保留忽略目录下的指定文件夹
|
||||
/profile/*
|
||||
!/profile/example
|
||||
|
||||
1
ABOUT.md
1
ABOUT.md
@ -1 +1,2 @@
|
||||
哔哩哔哩(Bilibili)B 站主站助手、直播助手、直播抽奖、挂机升级、贴心小棉袄脚本、Lv6 离你仅有一步之遥~ - PHP 版(Personal)
|
||||
|
||||
|
||||
843
CHANGELOG.md
843
CHANGELOG.md
@ -1,843 +0,0 @@
|
||||
# Release Notes
|
||||
|
||||
# 本项目Log
|
||||
|
||||
[comment]: <> (<details>)
|
||||
|
||||
[comment]: <> ( <summary><strong>更新历史</strong><kbd>latest</kbd></summary>)
|
||||
|
||||
[comment]: <> (</details>)
|
||||
|
||||
## v1.1.0.220218 alpha (2022-02-18)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意文档文件、配置文件有些许改动
|
||||
-
|
||||
|
||||
## v1.0.2.211115 alpha (2021-11-15)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加直播预约有奖
|
||||
- 添加企业微信群机器人推送
|
||||
- 添加企业微信应用消息推送
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 清理部分无效活动
|
||||
- 更新系统环境参数
|
||||
- 更新敏感关键字
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复登录未知错误
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意文档文件、配置文件有些许改动
|
||||
- 注意需要重新进行`composer update`操作
|
||||
- 注意只支持PHP8.* 只支持PHP8.* 只支持PHP8.*
|
||||
-
|
||||
|
||||
## v1.0.1.211014 alpha (2021-10-14)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新部分活动
|
||||
- 更新系统环境参数
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复中文用户名运行失败
|
||||
- 修复风纪(未完善,慎用)
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意文档文件有些许改动
|
||||
- 注意需要重新进行`composer update`操作
|
||||
- 注意只支持PHP8.* 只支持PHP8.* 只支持PHP8.*
|
||||
-
|
||||
|
||||
## v1.0.0.210822 alpha (2021-08-22)
|
||||
|
||||
### Added
|
||||
|
||||
- 支持自定义设备
|
||||
- 全面支持PHP8.0
|
||||
- 支持本地缓存
|
||||
- 对使用体验进行了一轮优化并解决了一些bug~~
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- PHP版本提升值8.*, 不向下兼容
|
||||
- 对使用体验进行了一轮优化并解决了一些bug~~
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 对使用体验进行了一轮优化并解决了一些bug~~
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意文档文件有些许改动
|
||||
- 注意需要重新进行`composer update`操作
|
||||
- 注意只支持PHP8.* 只支持PHP8.* 只支持PHP8.*
|
||||
-
|
||||
|
||||
## v0.9.9.210807 alpha (2021-08-07)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新基础环境参数
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复独立监控内存溢出
|
||||
- 修复天选之人统计数据不正确
|
||||
- 修复扭蛋活动只观看第一个任务
|
||||
- 修复脚本模式部分设备环境不兼容
|
||||
- 修复清理动态错误
|
||||
-
|
||||
|
||||
## v0.9.7.210714 alpha (2021-07-14)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加脚本模式 `php index.php -?`
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 省略
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 省略
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意配置文件有些许改动
|
||||
- 注意需要重新进行`composer update`操作
|
||||
-
|
||||
|
||||
## v0.9.6.210625 alpha (2021-06-25)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化动态过滤
|
||||
- 优化过滤关键字
|
||||
- 优化短信登录流程
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复动态转发
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意配置文件有些许改动
|
||||
-
|
||||
|
||||
## v0.9.5.210624 alpha (2021-06-24)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新动态转发
|
||||
- 更新基础环境参数
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 注意配置文件有些许改动
|
||||
-
|
||||
|
||||
## v0.9.4.210623 alpha (2021-06-23)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新部分仓库文件
|
||||
- 更新基础环境参数
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复PC端银瓜子兑换硬币
|
||||
- 修复主站投币任务
|
||||
- 修复点亮勋章特殊情况
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
-
|
||||
|
||||
## v0.9.3.210616 alpha (2021-06-16)
|
||||
|
||||
### Added
|
||||
|
||||
- 任务排程
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 配置热更新
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复弹幕
|
||||
- 修复独立监控
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
-
|
||||
|
||||
## v0.9.2.210602 alpha (2021-06-02)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新DcokerFile
|
||||
- 更新每日点亮勋章(100亲密度)
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
-
|
||||
|
||||
## v0.9.1.210518 alpha (2021-05-18)
|
||||
|
||||
### Added
|
||||
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 删除过期活动
|
||||
- 更新風機委員
|
||||
- 更新银瓜子兑换硬币
|
||||
- 更新点亮勋章
|
||||
- 更新部分日志打印输出
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复已知BUG
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
-
|
||||
|
||||
## v0.9.0.210517 alpha (2021-05-17)
|
||||
|
||||
### Added
|
||||
|
||||
- 重大更新
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 懒得写描述
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 配置文件有变动
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 请重新配置
|
||||
-
|
||||
|
||||
## v0.8.1.210423 alpha (2021-04-23)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新天选敏感词
|
||||
- 更新活动列表
|
||||
- 优化直播间心跳
|
||||
-
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
### Remarks
|
||||
-
|
||||
|
||||
## v0.8.0.210327 alpha (2021-03-27)
|
||||
|
||||
### Added
|
||||
|
||||
- 增加直播扭蛋抽奖活动(可自定义)
|
||||
- 增加主站九宫格抽奖活动(可自定义)
|
||||
- 增加多个推送消息通道
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新过滤词独立
|
||||
- 更新请求中心
|
||||
- 更新日志打印
|
||||
- 更新基础库
|
||||
- 更新环境读取流程
|
||||
- 更新部分配置
|
||||
- 更新登录请求
|
||||
- 更新实物抽奖&天选抽奖
|
||||
- 支持PHP8.0+
|
||||
- 更新弹幕抽奖
|
||||
- 更新每日任务
|
||||
- 更新部分任务架构
|
||||
- 引入必要新包
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复小心心心跳错误
|
||||
- 修复部分推送错误
|
||||
- 修复银瓜子换银币日志错误
|
||||
-
|
||||
|
||||
### Remarks
|
||||
|
||||
- 结构大更新,务必进行Composer等操作
|
||||
-
|
||||
|
||||
## v0.6.7.201117 alpha (2020-11-17)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 调整WS读取数据大小
|
||||
- 调整弹幕发送时间
|
||||
- 更新天选之子日志打印
|
||||
- 更新基础库
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复小心心心跳错误
|
||||
-
|
||||
|
||||
## v0.6.5.200808 alpha (2020-08-08)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加小心心支持
|
||||
- 添加活动抽奖
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 去掉无效双端观看
|
||||
- 过期小心心赠送
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复小心心心跳错误
|
||||
-
|
||||
|
||||
## v0.6.0.200730 alpha (2020-07-30)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加小心心支持
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新天选过滤关键词
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复节奏风暴逻辑错误
|
||||
-
|
||||
|
||||
## v0.5.0.200625 alpha (2020-06-25)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加破产机(赔到破产)
|
||||
- 添加推送KEY到期通知
|
||||
- 添加天选自动取关(测试)
|
||||
- 添加收益统计
|
||||
- 添加关注投币模式
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新部分信息输出
|
||||
- 修改日志打印前缀
|
||||
- 更新活跃弹幕延迟
|
||||
- 重构部分统计代码
|
||||
- 更新视频投币逻辑
|
||||
- 更新实物抽奖API
|
||||
- 修改硬币兑换延迟
|
||||
- 重构部分登录逻辑
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复日志输出错误
|
||||
- 修复每日送礼异常
|
||||
- 修复赛事逻辑错误
|
||||
- 修复部分已知问题
|
||||
-
|
||||
|
||||
## v0.4.0.200505 alpha (2020-05-05)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 关闭已结束的LPL赛事任务
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复日志回调空格解析异常
|
||||
- 修复节奏风暴回显过滤错误
|
||||
- 修复活动抽奖重复请求问题
|
||||
- 修复主站任务获取AID异常
|
||||
-
|
||||
|
||||
## v0.4.0.200428 alpha (2020-04-28)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复赠送礼物逻辑
|
||||
-
|
||||
|
||||
## v0.4.0.200426 alpha (2020-04-26)
|
||||
|
||||
### Added
|
||||
|
||||
- 赛事助手 (签到、分享)
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复休眠机制
|
||||
-
|
||||
|
||||
## v0.3.0.200425 alpha (2020-04-25)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加调用函数
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 取消一处请求头
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复休眠机制
|
||||
-
|
||||
|
||||
## v0.3.0.200424 alpha (2020-04-24)
|
||||
|
||||
### Added
|
||||
|
||||
- 抽出独立小黑屋
|
||||
- 提前引入BV2AV
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化监控推送
|
||||
- 优化登录参数
|
||||
- 同步黑屋提醒
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复监控输出
|
||||
-
|
||||
|
||||
## v0.3.0.200421 alpha (2020-04-21)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复节奏风暴回显
|
||||
- 修复分区监控异常
|
||||
- 修复获取勋章异常
|
||||
-
|
||||
|
||||
## v0.3.0.200419 alpha (2020-04-19)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 去除主监控
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复风暴回显过滤
|
||||
- 修复一处舰长处理
|
||||
- 修复中奖记录通知
|
||||
- 修复分区监控异常
|
||||
- 修复获取勋章异常
|
||||
-
|
||||
|
||||
## v0.3.0.200410 alpha (2020-04-10)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复备用监控无法获取
|
||||
- 修复获取分区ID异常
|
||||
-
|
||||
|
||||
## v0.3.0.200404 alpha (2020-04-04)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加ISSUE模板
|
||||
- 添加处理监控端命令
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复主监控内存溢出
|
||||
- 修复活动礼物提醒
|
||||
-
|
||||
|
||||
## v0.3.0.200318 alpha (2020-03-18)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加日常任务定时执行(AM10:00)
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- Sleep->Schedule
|
||||
- 优化异常通知
|
||||
- 优化异常重试数
|
||||
- 优化弹幕获取
|
||||
- 优化银瓜子宝箱
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复日志回调
|
||||
- 修复response为null
|
||||
- 修复PC端心跳
|
||||
- 修复部分已知
|
||||
-
|
||||
|
||||
## v0.3.0.200316 alpha (2020-03-16)
|
||||
|
||||
### Added
|
||||
|
||||
- 添加异常处理(通知)
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复活跃弹幕
|
||||
- 修复风纪测试
|
||||
- 修复部分已知
|
||||
-
|
||||
|
||||
## v0.3.0.200312 alpha (2020-03-12)
|
||||
|
||||
### Added
|
||||
|
||||
- 引入风纪 (不稳定测试)
|
||||
- 引入新库 (需要重新Composer)
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 重构部分公用方法
|
||||
- 重构CURL请求
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复登录繁忙
|
||||
- 修复实物抽奖
|
||||
- 修复日志输出
|
||||
- 修复部分已知
|
||||
-
|
||||
|
||||
## v0.2.0.200226 alpha (2020-02-26)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复节奏风暴
|
||||
- 修复双端心跳
|
||||
-
|
||||
|
||||
## v0.2.0.200224 alpha (2020-02-24)
|
||||
|
||||
### Added
|
||||
|
||||
- 新增工具类
|
||||
- 引入新库(需要重新Composer)
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化数据过滤条件
|
||||
- 更新PC端心跳API
|
||||
- 优化实物抽奖
|
||||
- 优化运行条件
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复内存异常
|
||||
- 修复重复投币
|
||||
-
|
||||
|
||||
## v0.2.0.200214 alpha (2020-02-14)
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化实物抽奖流程
|
||||
- 优化延迟礼物抽奖
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修正部分函数名称
|
||||
- 尝试减少静态占用
|
||||
-
|
||||
|
||||
## v0.2.0.200208 alpha (2020-02-08)
|
||||
|
||||
### Added
|
||||
|
||||
- 哔哩哔哩漫画助手(可选)
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 补充部分过滤关键字
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复一处内存异常
|
||||
-
|
||||
|
||||
## v0.1.0.200111 alpha (2020-01-11)
|
||||
|
||||
### Added
|
||||
|
||||
- 天选时刻奖品过滤
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## v0.1.0.200128 alpha (2020-01-28)
|
||||
|
||||
### Added
|
||||
|
||||
- 增加推送消息过滤
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复抽奖推送错误
|
||||
-
|
||||
|
||||
## v0.1.0.200111 alpha (2020-01-11)
|
||||
|
||||
### Added
|
||||
|
||||
- 天选时刻奖品过滤
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## v0.1.0.200103 alpha (2020-01-03)
|
||||
|
||||
### Added
|
||||
|
||||
- 增加并发请求
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 更新抽奖逻辑
|
||||
- 更新部分API
|
||||
- 减少重复请求
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复部分回显错误
|
||||
-
|
||||
|
||||
## v0.1.0.200101 alpha (2020-01-01)
|
||||
|
||||
### Added
|
||||
|
||||
- 任务逻辑引入协程
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复礼物赠送异常
|
||||
-
|
||||
|
||||
## v0.1.0.191227 alpha (2019-12-27)
|
||||
|
||||
### Added
|
||||
|
||||
- 新增备用官方分区监控
|
||||
- 新增按勋章亲密度赠送
|
||||
- 新增天选时刻获奖推送
|
||||
-
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化部分架构
|
||||
- 优化独立监控
|
||||
- 优化监控逻辑
|
||||
- 优化礼物赠送
|
||||
- 优化通用抽奖
|
||||
- 优化推送逻辑
|
||||
-
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复部分日志显示
|
||||
- 修复数据统计异常
|
||||
- 修复瓜子宝箱异常
|
||||
- 修复Server酱异常
|
||||
- 修复天选时刻异常
|
||||
- 修复抽奖数据异常
|
||||
- 修复部分已知BUG
|
||||
- 修复获奖推送通知
|
||||
- 修复休眠中心异常
|
||||
- 修复礼物赠送异常
|
||||
-
|
||||
|
||||
## v0.0.5.191223 alpha (2019-12-23)
|
||||
|
||||
## v0.0.4.191030 alpha (2019-10-30)
|
||||
|
||||
## v0.0.3.190730 alpha (2019-07-30)
|
||||
|
||||
## v0.0.2.190723 alpha (2019-07-23)
|
||||
|
||||
## v0.0.1.190713 alpha (2019-07-13)
|
||||
338
DOC.md
338
DOC.md
@ -1,338 +0,0 @@
|
||||
<p align="center"><img width="300px" src="https://user-images.githubusercontent.com/19500576/118621710-36428180-b7f9-11eb-891d-3f5697347cef.png"></p>
|
||||
|
||||
[comment]: <> (<p align="center"><img width="300px" src="https://i.loli.net/2018/04/20/5ad97bd395912.jpeg"></p>)
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/lkeme/ )
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## 环境依赖
|
||||
|
||||
通常使用 `composer` 工具会自动检测以下依赖问题。
|
||||
|
||||
|Requirement |
|
||||
|--------------------|
|
||||
|PHP >=8.0 |
|
||||
|php_curl |
|
||||
|php_sockets |
|
||||
|php_openssl |
|
||||
|php_json |
|
||||
|php_zlib |
|
||||
|php_mbstring |
|
||||
|
||||
## Composer
|
||||
|
||||
+ [Composer 安装与使用](https://www.runoob.com/w3cnote/composer-install-and-usage.html)
|
||||
|
||||
+ [Composer 下载](https://getcomposer.org/download/)
|
||||
|
||||
+ 当前项目 `composer.lock` 基于阿里云 Composer镜像生成
|
||||
|
||||
+ 阿里云(全量镜像)
|
||||
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://developer.aliyun.com/composer
|
||||
# 使用命令
|
||||
> composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
||||
```
|
||||
|
||||
+ 恢复默认镜像|Composer.phar加速下载
|
||||
|
||||
```shell script
|
||||
> composer config -g --unset repos.packagist
|
||||
|
||||
> https://mirrors.cloud.tencent.com/composer/composer.phar
|
||||
> https://mirrors.aliyun.com/composer/composer.phar
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>其余镜像 展开查看</summary>
|
||||
<pre><code>
|
||||
+ cnpkg(全量镜像)
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://php.cnpkg.org/
|
||||
# 使用命令
|
||||
> composer config -g repos.packagist composer https://php.cnpkg.org
|
||||
```
|
||||
|
||||
+ 腾讯云(全量镜像)
|
||||
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://mirrors.cloud.tencent.com/help/composer.html
|
||||
# 使用命令
|
||||
> composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/
|
||||
```
|
||||
|
||||
+ PhpComposer(全量镜像)
|
||||
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://pkg.phpcomposer.com/
|
||||
# 使用命令
|
||||
> composer config -g repo.packagist composer https://packagist.phpcomposer.com
|
||||
```
|
||||
|
||||
+ 华为云(全量镜像)
|
||||
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://mirrors.huaweicloud.com/repository/php/
|
||||
# 使用命令
|
||||
> composer config -g repos.packagist composer https://mirrors.huaweicloud.com/repository/php/
|
||||
```
|
||||
|
||||
+ 交通大学(非全量镜像)
|
||||
|
||||
```shell script
|
||||
# 使用帮助
|
||||
> https://packagist.mirrors.sjtug.sjtu.edu.cn/
|
||||
# 使用命令
|
||||
> composer config -g repos.packagist composer https://packagist.mirrors.sjtug.sjtu.edu.cn
|
||||
```
|
||||
|
||||
</code></pre>
|
||||
</details>
|
||||
|
||||
## 使用指南
|
||||
|
||||
1. 下载(克隆)项目代码,初始化项目
|
||||
|
||||
```shell script
|
||||
$ git clone https://github.com/lkeme/BiliHelper-personal.git
|
||||
$ cd BiliHelper-personal/conf
|
||||
$ cp user.ini.example user.ini
|
||||
```
|
||||
|
||||
2. 使用 [composer](https://getcomposer.org/download/) 工具进行安装
|
||||
|
||||
```shell script
|
||||
$ composer install
|
||||
```
|
||||
|
||||
[comment]: <> (composer dump-autoload (-o))
|
||||
|
||||
[comment]: <> (composer dumpautoload (-o))
|
||||
|
||||
3. 按照说明修改配置文件 `user.ini`
|
||||
|
||||
```shell script
|
||||
# 默认只需填写帐号密码,按需求开启其他功能即可
|
||||
...
|
||||
```
|
||||
|
||||
4. 运行测试
|
||||
|
||||
```shell script
|
||||
$ php index.php
|
||||
```
|
||||
|
||||
> 以下是`多账户多开方案`,单个账户可以无视
|
||||
|
||||
5. 复制一份example配置文件,修改账号密码即可
|
||||
|
||||
```shell script
|
||||
$ php index.php example.ini
|
||||
```
|
||||
|
||||
6. 自定义设备方案
|
||||
|
||||
```shell script
|
||||
$ cd conf
|
||||
$ cp bili.yaml user_bili.yaml
|
||||
$ cp device.yaml user_device.yaml
|
||||
```
|
||||
|
||||
7. 命令模式
|
||||
|
||||
```shell script
|
||||
# 获取所有命令
|
||||
$ php index.php -?
|
||||
```
|
||||
|
||||
8. 请保证配置文件存在,否则默认加载`user.ini`配置文件
|
||||
|
||||
<p align="center"><img width="680px" src="https://user-images.githubusercontent.com/19500576/118621472-f8455d80-b7f8-11eb-9fec-500148a566b4.png"></p>
|
||||
|
||||
[comment]: <> (<p align="center"><img width="680px" src="https://i.loli.net/2018/04/21/5adb497dc3ece.png"></p>)
|
||||
|
||||
## Docker使用指南
|
||||
|
||||
1. 安装好[Docker](https://yeasy.gitbooks.io/docker_practice/content/install/)
|
||||
2. 直接命令行拉取镜像后运行
|
||||
|
||||
### 传入的参数方式有两种(二选一,如果同时传入则优先选择配置文件)
|
||||
|
||||
- 通过环境变量进行传入
|
||||
|
||||
```shell script
|
||||
$ docker run -itd --rm -e USER_NAME=你的B站登录账号 -e USER_PASSWORD=你的B站密码 lkeme/bilihelper-personal
|
||||
```
|
||||
|
||||
- 通过配置文件进行传入(能保留登录状态,自定义配置)
|
||||
|
||||
1. 下载[配置文件](https://raw.githubusercontent.com/lkeme/BiliHelper-personal/master/conf/user.ini.example)
|
||||
2. 修改
|
||||
3. 通过下面的命令进行挂载并运行
|
||||
|
||||
```shell script
|
||||
$ docker run -itd --rm -v /path/to/your/confFileName.ini:/app/conf/user.ini lkeme/bilihelper-personal
|
||||
```
|
||||
|
||||
- 使用github镜像加速
|
||||
|
||||
```shell script
|
||||
$ -e MIRRORS=0 # 使用 github.com
|
||||
$ -e MIRRORS=1 # 使用 ghproxy.com
|
||||
$ -e MIRRORS=2 # 使用 fastgit.org
|
||||
$ -e MIRRORS=3 # 使用 hub.gitfast.tk
|
||||
$ -e MIRRORS=4 # 使用 hub.gitslow.tk
|
||||
$ -e MIRRORS=5 # 使用 hub.verge.tk
|
||||
$ -e MIRRORS=6 # 使用 gh.api.99988866.xyz
|
||||
$ -e MIRRORS=custom -e CUSTOM_CLONE_URL=https://github.com/lkeme/BiliHelper-personal.git # 使用 自定义克隆地址
|
||||
```
|
||||
|
||||
- 相关参数
|
||||
|
||||
```ps
|
||||
-it 前台运行
|
||||
-itd 后台运行
|
||||
-v 本地文件:容器内部文件 ==> 挂载本地文件到容器中。本地文件路径随便变,容器内部文件路径不能变。
|
||||
```
|
||||
|
||||
- -v模式使用短信登录
|
||||
|
||||
```
|
||||
配置文件里设置好,发送完短信
|
||||
docker attach 或者docker exec 再进去容器里输入
|
||||
```
|
||||
|
||||
- 注意: Docker镜像已经包含了所有所需的运行环境,无需在本地环境弄composer。每次启动容器时,都会与项目进行同步以确保版本最新。
|
||||
|
||||
## 升级指南
|
||||
|
||||
> 注意新版本的配置文件是否变动,则需要重新覆盖配置文件,并重新填写设置
|
||||
|
||||
1. 进入项目目录
|
||||
|
||||
```
|
||||
$ cd BiliHelper-personal
|
||||
```
|
||||
|
||||
2. 拉取最新代码
|
||||
|
||||
```
|
||||
$ git pull
|
||||
```
|
||||
|
||||
3. 更新依赖库
|
||||
|
||||
```
|
||||
$ composer install
|
||||
```
|
||||
|
||||
4. 如果使用 systemd 等,需要重启服务
|
||||
|
||||
```
|
||||
$ systemctl restart bilibili
|
||||
```
|
||||
|
||||
## 部署指南
|
||||
|
||||
如果你将 BiliHelper-personal 部署到线上服务器时,则需要配置一个进程监控器来监测 `php index.php` 命令,在它意外退出时自动重启。
|
||||
|
||||
通常可以使用以下的方式
|
||||
|
||||
- systemd (推荐)
|
||||
- Supervisor
|
||||
- screen (自用)
|
||||
- nohup
|
||||
|
||||
## systemd 脚本
|
||||
|
||||
```
|
||||
# /usr/lib/systemd/system/bilibili.service
|
||||
|
||||
[Unit]
|
||||
Description=BiliHelper Manager
|
||||
Documentation=https://github.com/lkeme/BiliHelper-personal
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/php /path/to/your/BiliHelper-personal/index.php
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## Supervisor 配置
|
||||
|
||||
```
|
||||
[program:bilibili]
|
||||
process_name=%(program_name)s
|
||||
command=php /path/to/your/BiliHelper-personal/index.php
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/tmp/bilibili.log
|
||||
```
|
||||
|
||||
## 报错通知问题
|
||||
|
||||
脚本出现 error 级别的报错,会调用通知地址进行提醒,这里推荐两个服务
|
||||
|
||||
|服务|官网|
|
||||
|---|---|
|
||||
|Server酱|https://sc.ftqq.com/|
|
||||
|TelegramBot|https://core.telegram.org/bots/api|
|
||||
|
||||
示范如下
|
||||
|
||||
```
|
||||
# Server酱
|
||||
# 自行替换 <SCKEY>
|
||||
APP_CALLBACK="https://sc.ftqq.com/<SCKEY>.send?text={message}"
|
||||
|
||||
# TelegramBot
|
||||
# 自行替换 <TOKEN> <CHAR_ID>
|
||||
APP_CALLBACK="https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<CHAR_ID>&text={message}"
|
||||
```
|
||||
|
||||
`{message}` 部分会自动替换成错误信息,接口采用 get 方式发送
|
||||
|
||||
## 直播间 ID 问题
|
||||
|
||||
文件 `user.ini` 里
|
||||
|
||||
`ROOM_ID` 配置,填写此项可以清空临过期礼物给指定直播间。
|
||||
|
||||
`ROOM_LIST` 配置,使用长位直播间,填写此项可以清空临礼物给指定有勋章的直播间。
|
||||
|
||||
`FEED_FILL` 配置,搭配上一条使用,使用过期礼物或者倒序使用正常礼物。
|
||||
|
||||
`SOCKET_ROOM_ID` 配置,监控使用,暂时没用到。
|
||||
|
||||
通常可以在直播间页面的 url 获取到它
|
||||
|
||||
```
|
||||
http://live.bilibili.com/9522051
|
||||
```
|
||||
|
||||
长位直播间ID获取
|
||||
|
||||
```
|
||||
https://api.live.bilibili.com/room/v1/Room/room_init?id=3
|
||||
```
|
||||
|
||||
所有直播间号码小于 1000 的直播间为短号,部分4位直播间也为短号,
|
||||
|
||||
该脚本在每次启动会自动修正部分功能,特殊标注的请留意。
|
||||
132
NOTIFY.md
132
NOTIFY.md
@ -1,132 +0,0 @@
|
||||
## 关于推送
|
||||
|
||||
### 开关
|
||||
|
||||
```ini
|
||||
[notify]
|
||||
enable = false
|
||||
filter_words =
|
||||
```
|
||||
|
||||
### 推送单元
|
||||
|
||||
> 以下数据为示例(e.g.),需要根据实际需求配置
|
||||
|
||||
**钉钉**
|
||||
|
||||
> 文档: https://developers.dingtalk.com/document/robots/custom-robot-access
|
||||
> 说明: 钉钉推送的密钥
|
||||
|
||||
```ini
|
||||
; Dingtalk机器人|token|依赖USE_NOTIFY
|
||||
[notify.dingtalk]
|
||||
token = 566cc69da782ec****
|
||||
```
|
||||
|
||||
**Telegram**
|
||||
|
||||
> 文档: https://core.telegram.org/bots/api#sendmessage
|
||||
> 说明: 如果开启 TGbot API 反代,填写url,否则为空使用默认api。
|
||||
> 说明: TG 推送的Token, xxx/bot{这是token部分}/xxxx
|
||||
> 说明: TG 推送的用户/群组/频道 ID
|
||||
|
||||
```ini
|
||||
; Tele机器人|url(可选)|token|chatid|依赖USE_NOTIFY
|
||||
[notify.telegram]
|
||||
url = https://*.*.workers.dev/bot
|
||||
bottoken = 1640****:AAGlV3****_FscZ-****
|
||||
chatid = 390****
|
||||
```
|
||||
|
||||
**PUSH PLUS**
|
||||
|
||||
> 文档: http://www.pushplus.plus/doc/
|
||||
> 说明: push plus++ 推送的 `token`
|
||||
|
||||
```ini
|
||||
; Pushplus酱|token|依赖USE_NOTIFY
|
||||
[notify.pushplus]
|
||||
token = 566cc69da782ec****
|
||||
```
|
||||
|
||||
**Sever酱(原版)**
|
||||
|
||||
> 文档: https://sc.ftqq.com/
|
||||
> 说明: Server 酱老版本 key,SCU 开头的
|
||||
|
||||
```ini
|
||||
; Sever酱(原版)|令牌Key|依赖USE_NOTIFY
|
||||
[notify.sc]
|
||||
sckey = SCU566cc69da782ec****
|
||||
```
|
||||
|
||||
**Server酱(Turbo版)**
|
||||
|
||||
> 文档: https://sct.ftqq.com/
|
||||
> 说明: Server 酱 Turbo 版本 key,SCT 开头的
|
||||
|
||||
```ini
|
||||
; Server酱(Turbo版)|令牌Key|依赖USE_NOTIFY
|
||||
[notify.sct]
|
||||
sctkey = SCT566cc69da782ec****
|
||||
```
|
||||
|
||||
**GoCqhttp**
|
||||
|
||||
> 文档: https://docs.go-cqhttp.org/api/
|
||||
> 说明: 推送的完整api, 包含`/send_private_msg`、`/send_group_msg` 等等完整后缀
|
||||
> 说明: 推送的AccessToken
|
||||
> 说明: 目标QQ号或者QQ群号,根据API调整
|
||||
|
||||
```ini
|
||||
; GoCqhttp|url|token|目标qq|依赖USE_NOTIFY
|
||||
[notify.gocqhttp]
|
||||
url = "http://127.0.0.1:5700/send_private_msg"
|
||||
token = 566cc69da782ec****
|
||||
target_qq = 10086
|
||||
```
|
||||
|
||||
**Debug(个人用)**
|
||||
|
||||
> 文档: https://localhost:8921/doc
|
||||
|
||||
```ini
|
||||
; Debug|个人调试推送|url|token|
|
||||
[notify.debug]
|
||||
url = "https://localhost:8921/notify"
|
||||
token = 566cc69da782ec****
|
||||
```
|
||||
|
||||
**企业微信群机器人**
|
||||
|
||||
> 文档: https://open.work.weixin.qq.com/api/doc/90000/90136/91770 | https://weibanzhushou.com/blog/330
|
||||
> 说明: 推送的AccessToken
|
||||
|
||||
```ini
|
||||
; 企业微信群机器人|token
|
||||
[notify.we_com]
|
||||
token = ec971f1d-****-4700-****-d9461e76****
|
||||
```
|
||||
|
||||
**企业微信应用**
|
||||
|
||||
> 文档: https://open.work.weixin.qq.com/wwopen/devtool/interface?doc_id=10167
|
||||
> 说明: 企业 id
|
||||
> 说明: 应用的凭证密钥
|
||||
> 说明: 企业应用的 id
|
||||
> 说明: 指定接收消息的成员,成员 ID 列表 默认为@all
|
||||
|
||||
```ini
|
||||
; 企业微信应用消息|corp_id|corp_secret|agent_id|to_user
|
||||
[notify.we_com_app]
|
||||
corp_id = ****
|
||||
corp_secret = ****
|
||||
agent_id = ****
|
||||
to_user = UserId1|UserId2|UserId3
|
||||
```
|
||||
|
||||
### 调试
|
||||
|
||||
https://github.com/lkeme/BiliHelper-personal/blob/eb06f55fa0fa6cb07bbeffc7e85c6ac0bfaa67b3/data/latest_version.json#L8
|
||||
|
||||
改成与线上不同的版本即可,检查新版本就会推送一次。
|
||||
153
README.md
153
README.md
@ -1,153 +0,0 @@
|
||||
<p align="center"><img width="300px" src="https://user-images.githubusercontent.com/19500576/118621710-36428180-b7f9-11eb-891d-3f5697347cef.png"></p>
|
||||
|
||||
[comment]: <> (<p align="center"><img width="300px" src="https://i.loli.net/2018/04/20/5ad97bd395912.jpeg"></p>)
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/lkeme/ )
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
[](https://hub.docker.com/r/lkeme/bilihelper-personal)
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<img src="https://img.shields.io/badge/Version-1.1.0.220218-orange.svg?longCache=true&style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/PHP-8.0+-green.svg?longCache=true&style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/Composer-latest-blueviolet.svg?longCache=true&style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/License-mit-blue.svg?longCache=true&style=for-the-badge">
|
||||
|
||||
</p>
|
||||
|
||||
## 📌公告通知
|
||||
|
||||
代码开源,本地化99.9%,项目不收集或使用任何敏感信息,兴趣所致,一切只为学习。
|
||||
|
||||
```notice
|
||||
---- 免费的东西总是得不到人的珍惜。
|
||||
---- 只有花大价钱去买到的东西,才会令人信任。
|
||||
---- 本项目仅供学习交流使用,请勿用于非法用途!* 3
|
||||
```
|
||||
|
||||
## 👤游客访问
|
||||
|
||||
<p align="center">
|
||||
<img alingn="center" src="https://profile-counter.glitch.me/BiliHelper-personal/count.svg" />
|
||||
</p>
|
||||
|
||||
## 🎁打赏支持
|
||||
|
||||
如果觉得本项目好用,对你有所帮助,欢迎打赏支持本项目哦。
|
||||
|
||||
<p align="center"><img width="680px" src="https://user-images.githubusercontent.com/19500576/118621834-55d9aa00-b7f9-11eb-9de2-6cfd5e8f20e6.png"></p>
|
||||
|
||||
[comment]: <> ()
|
||||
|
||||
## 🖨️相关文档
|
||||
|
||||
有疑问一定要先看看文档或Issue里是否存在相同的问题,再考虑其他渠道咨询。
|
||||
|
||||
[comment]: <> (:cherry_blossom: :gift: :gift_heart: :confetti_ball:)
|
||||
|
||||
* [使用文档 / DOC.md](./DOC.md)
|
||||
* [推送文档 / DOC.md](./NOTIFY.md)
|
||||
* [更新日志 / CHANGELOG.md](./CHANGELOG.md)
|
||||
* [配置文档 / WIKI.md](https://github.com/lkeme/BiliHelper-personal/wiki/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%AF%A6%E8%A7%A3)
|
||||
* [常见问题 / WIKI.md](https://github.com/lkeme/BiliHelper-personal/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
|
||||
|
||||
## 💬交流反馈
|
||||
|
||||
Group: [163955623](https://jq.qq.com/?_wv=1027&k=1QMFTUEO) | **请不要来问如何使用, 文档齐全, 仅用于BUG提交反馈**
|
||||
|
||||
## 🧑🏭功能组件
|
||||
|
||||
以下任务都是按设定周期自动执行,`true`为正常使用,`false`为暂停使用或抛弃。
|
||||
|
||||
<details open>
|
||||
<summary>点击展开</summary>
|
||||
|
||||
| plugin | status | version | cycle | description |
|
||||
|-----------------|--------|----------|-------|-------------------------|
|
||||
| CheckUpdate | true | 22.01.18 | 待整理 | 程序检查更新 |
|
||||
| Login | true | 22.01.18 | 待整理 | 账号登录、刷新、维持 |
|
||||
| Schedule | true | 22.01.18 | 待整理 | 控制插件运行周期 |
|
||||
| MainSite | true | 22.01.18 | 待整理 | 投币、观看、分享视频 (速升6级不是梦) |
|
||||
| DailyBag | true | 22.01.18 | 待整理 | 双端领取日常/周常礼包 |
|
||||
| ManGa | true | 22.01.18 | 待整理 | 漫画签到、分享 |
|
||||
| ActivityLottery | true | 22.01.18 | 待整理 | 主站活动九宫格抽奖 |
|
||||
| Competition | true | 22.01.18 | 待整理 | 游戏赛事竞猜 |
|
||||
| DoubleHeart | true | 22.01.18 | 待整理 | 双端心跳 (姥爷直播经验) |
|
||||
| DailyTask | true | 22.01.18 | 待整理 | 直播每日任务(签到、观看) |
|
||||
| Barrage | true | 22.01.18 | 待整理 | 保持活跃弹幕 |
|
||||
| Silver2Coin | true | 22.01.18 | 待整理 | 银瓜子兑换硬币 |
|
||||
| Judge | true | 22.01.18 | 待整理 | 風機委員投票 |
|
||||
| GiftSend | true | 22.01.18 | 待整理 | 礼物赠送、维持每日勋章亲密度 |
|
||||
| GroupSignIn | true | 22.01.18 | 待整理 | 友爱社签到 |
|
||||
| GiftHeart | true | 22.01.18 | 待整理 | 日常心跳每日礼包礼物 |
|
||||
| SmallHeart | true | 22.01.18 | 待整理 | 直播挂机,每日24个小心心 |
|
||||
| MaterialObject | true | 22.01.18 | 待整理 | 直播金色宝箱实物抽奖 |
|
||||
| AloneTcpClient | true | 22.01.18 | 待整理 | 作者的独立直播监控(可支持本项目哦) |
|
||||
| ZoneTcpClient | true | 22.01.18 | 待整理 | 官方的分区直播监控 |
|
||||
| StormRaffle | true | 22.01.18 | 待整理 | 直播节奏风暴抽奖、亿元 |
|
||||
| GiftRaffle | true | 22.01.18 | 待整理 | 直播礼物抽奖 |
|
||||
| PkRaffle | true | 22.01.18 | 待整理 | 直播大乱斗抽奖 |
|
||||
| GuardRaffle | true | 22.01.18 | 待整理 | 直播大航海抽奖 |
|
||||
| AnchorRaffle | true | 22.01.18 | 待整理 | 直播天选时刻抽奖 |
|
||||
| GiftRaffle | true | 22.01.18 | 待整理 | 直播礼物抽奖 |
|
||||
| AwardRecord | true | 22.01.18 | 待整理 | 最新的中奖纪录通知 |
|
||||
| Forward | true | 22.01.18 | 待整理 | 主站动态抽奖转发 |
|
||||
| CapsuleLottery | true | 22.01.18 | 待整理 | 直播扭蛋活动抽奖 |
|
||||
| PolishTheMedal | true | 22.01.18 | 待整理 | 每日自动点亮灰色勋章 |
|
||||
| CapsuleLottery | true | 22.01.18 | 待整理 | 直播扭蛋活动抽奖 |
|
||||
| VipPrivilege | true | 22.01.18 | 待整理 | 每月领取年度大会员特权(B币券、会员购优惠券) |
|
||||
| BpConsumption | true | 22.01.18 | 待整理 | 每月消费使用年度大会员特权的B币券 |
|
||||
| Statistics | true | 22.01.18 | 待整理 | 全局抽奖结果统计 |
|
||||
| LiveReservation | true | 22.01.18 | 待整理 | 直播预约有奖 |
|
||||
| Silver | false | 21.03.27 | 待整理 | 直播银瓜子自动开启宝箱 |
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## 🖥️星图
|
||||
|
||||
[](https://starchart.cc/lkeme/BiliHelper-personal)
|
||||
[](https://starchart.cc/lkeme/BiliHelper)
|
||||
|
||||
## 运行效果
|
||||
|
||||
效果图不代表当前版本,请以当前最新版本运行结果为准。
|
||||
|
||||
<p align="center"><img width="680px" src="https://user-images.githubusercontent.com/19500576/118621918-6853e380-b7f9-11eb-8c73-e041c402a56b.png"></p>
|
||||
|
||||
[comment]: <> ()
|
||||
|
||||
## 项目相关
|
||||
|
||||
* [BilibiliHelper](https://github.com/metowolf/BilibiliHelper)
|
||||
* [BiliHelper](https://github.com/lkeme/BiliHelper)
|
||||
* [Github](https://github.com/)
|
||||
|
||||
## 致谢
|
||||
|
||||
感谢 `JetBrains` 提供优秀的IDE。
|
||||
|
||||
<a href="https://www.jetbrains.com/?from=BiliHelper-personal" target="_blank">
|
||||
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gov9g3tzrnj30u00wj0tn.jpg" width="150"/>
|
||||
</a>
|
||||
|
||||
## License 许可证
|
||||
|
||||
BiliHelper is under the MIT license.
|
||||
|
||||
本项目基于 MIT 协议发布,并增加了 SATA 协议。
|
||||
|
||||
当你使用了使用 SATA 的开源软件或文档的时候,在遵守基础许可证的前提下,你必须马不停蹄地给你所使用的开源项目 “点赞” ,比如在 GitHub 上
|
||||
star,然后你必须感谢这个帮助了你的开源项目的作者,作者信息可以在许可证头部的版权声明部分找到。
|
||||
|
||||
本项目的所有代码文件、配置项,除另有说明外,均基于上述介绍的协议发布,具体请看分支下的 LICENSE。
|
||||
|
||||
此处的文字仅用于说明,条款以 LICENSE 文件中的内容为准。
|
||||
@ -1,31 +1,24 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$app = new BiliHelper\Core\App(__DIR__);
|
||||
$app->load($argv)
|
||||
->inspect()
|
||||
->start();
|
||||
|
||||
$app = Bhp\Bootstrap\Bootstrap::getInstance(__DIR__,$argv);
|
||||
$app->run();
|
||||
|
||||
@ -1,7 +1,46 @@
|
||||
{
|
||||
"name": "lkeme/bilihelper",
|
||||
"name": "lkeme/bilihelper-personal",
|
||||
"description": "B 站自动领瓜子、直播助手、直播挂机脚本、主站助手 - PHP 版(Personal)",
|
||||
"type": "project",
|
||||
"version": "1.0.0-dev",
|
||||
"minimum-stability": "stable",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lkeme",
|
||||
"email": "Useri@live.cn",
|
||||
"homepage": "https://mudew.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/lkeme/BiliHelper-personal",
|
||||
"readme": "https://github.com/lkeme/BiliHelper-personal/blob/master/README.md",
|
||||
"support": {
|
||||
"issues": "https://github.com/lkeme/BiliHelper-personal/issues?state=open",
|
||||
"wiki": "https://github.com/lkeme/BiliHelper-personal/wiki",
|
||||
"source": "https://github.com/lkeme/BiliHelper-personal"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"description": "阿里云(全量)/1Min",
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.aliyun.com/composer/",
|
||||
"canonical": false
|
||||
},
|
||||
{
|
||||
"description": "华为云(全量)",
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.huaweicloud.com/repository/php/",
|
||||
"canonical": false
|
||||
},
|
||||
{
|
||||
"description": "PhpComposer(全量)",
|
||||
"type": "composer",
|
||||
"url": "https://packagist.phpcomposer.com",
|
||||
"canonical": false
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"ext-curl": "*",
|
||||
@ -10,41 +49,26 @@
|
||||
"ext-json": "*",
|
||||
"ext-zlib": "*",
|
||||
"ext-mbstring": "*",
|
||||
"monolog/monolog": "^1.26.0",
|
||||
"bramus/monolog-colored-line-formatter": "^2.0.3",
|
||||
"clue/socket-raw": "^1.5.0",
|
||||
"amphp/amp": "^2.5.2",
|
||||
"guzzlehttp/guzzle": "^7.4.0",
|
||||
"overtrue/pinyin": "~4.0",
|
||||
"adhocore/cli": "^0.9.0",
|
||||
"lkeme/inifile": "^3.4",
|
||||
"symfony/yaml": "^6.0",
|
||||
"sven/file-config": "^3.1",
|
||||
"fire015/flintstone": "^2.3",
|
||||
"consolidation/config": "^2.0",
|
||||
"lkeme/data": "dev-master",
|
||||
"phppkg/config": "^1.1"
|
||||
"monolog/monolog": "2.x-dev",
|
||||
"bramus/monolog-colored-line-formatter": "dev-master",
|
||||
"symfony/yaml": "6.1.x-dev",
|
||||
"toolkit/stdlib": "*",
|
||||
"adhocore/cli": "dev-main",
|
||||
"lkeme/data": "4.x-dev",
|
||||
"grasmash/expander": "dev-main",
|
||||
"amphp/amp": "^2.6.2",
|
||||
"fire015/flintstone": "dev-master",
|
||||
"overtrue/pinyin": "dev-master",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"toolkit/pflag": "^2.0",
|
||||
"symfony/console": "^6.1"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lkeme",
|
||||
"email": "Useri@live.cn",
|
||||
"homepage": "https://mudew.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BiliHelper\\Core\\": "src/core",
|
||||
"BiliHelper\\Plugin\\": "src/plugin",
|
||||
"BiliHelper\\Plugins\\": "src/plugins",
|
||||
"BiliHelper\\Util\\": "src/util",
|
||||
"BiliHelper\\Tool\\": "src/tool",
|
||||
"BiliHelper\\Script\\": "src/script",
|
||||
"BiliHelper\\Exceptions\\": "src/exception"
|
||||
"Bhp\\": "src"
|
||||
},
|
||||
"files": [
|
||||
"src/core/Helpers.php"
|
||||
"src/Helpers.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
bili_version: 0.0.1
|
||||
|
||||
# Android
|
||||
bili_a:
|
||||
package: "tv.danmaku.bili"
|
||||
version: "6.60.0"
|
||||
build: "6600300"
|
||||
channel: "bili"
|
||||
device: "phone"
|
||||
mobi_app: "android"
|
||||
platform: "android"
|
||||
s_locale: "zh-Hans_CN"
|
||||
c_locale: "zh-Hans_CH"
|
||||
app_key: "MWQ4YjZlN2Q0NTIzMzQzNg=="
|
||||
secret_key: "NTYwYzUyY2NkMjg4ZmVkMDQ1ODU5ZWQxOGJmZmQ5NzM"
|
||||
app_key_n: "NzgzYmJiNzI2NDQ1MWQ4Mg=="
|
||||
secret_key_n: "MjY1MzU4M2M4ODczZGVhMjY4YWI5Mzg2OTE4YjFkNjU="
|
||||
|
||||
# IOS
|
||||
bili_i:
|
||||
app_key: "MjdlYjUzZmM5MDU4ZjhjMw=="
|
||||
secret_key: "YzJlZDUzYTc0ZWVlZmUzY2Y5OWZiZDAxZDhjOWMzNzU="
|
||||
|
||||
# Tv
|
||||
bili_t:
|
||||
app_key: "NDQwOWUyY2U4ZmZkMTJiOA=="
|
||||
secret_key: "NTliNDNlMDRhZDY5NjVmMzQzMTkwNjJiNDc4ZjgzZGQ="
|
||||
@ -1,14 +0,0 @@
|
||||
device_version: 0.0.1
|
||||
|
||||
device:
|
||||
os: "android"
|
||||
os_ver: "7.1.2"
|
||||
model: "MuMu"
|
||||
network: "2" # 1 流量 2 WIFI
|
||||
|
||||
other_headers:
|
||||
ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
|
||||
pc_headers:
|
||||
ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"
|
||||
app_headers:
|
||||
ua: "Mozilla/5.0 BiliDroid/${bili_a.version} (bbcallen@gmail.com) os/${device.os} model/${device.model} mobi_app/${bili_a.mobi_app} build/${bili_a.build} channel/${bili_a.channel} innerVer/${bili_a.build} osVer/${device.os_ver} network/${device.network}"
|
||||
@ -1,313 +0,0 @@
|
||||
version = 0.0.1
|
||||
|
||||
#######################
|
||||
# 账户设置 #
|
||||
#######################
|
||||
|
||||
[login.account]
|
||||
; 帐号|密码
|
||||
username = ""
|
||||
password = ""
|
||||
|
||||
; 登录模式|[1.账密模式 2.短信验证码模式 3.行为验证码模式(暂未开放)]
|
||||
[login.mode]
|
||||
mode = 1
|
||||
|
||||
; 国家代码|mode=2触发|例:大陆86 澳大利亚61
|
||||
[login.country]
|
||||
country_code = 86
|
||||
|
||||
; 校验|mode=2触发|校验国内手机号|国外手机号关闭校验
|
||||
[login.check]
|
||||
phone = true
|
||||
|
||||
; UID|CSRF|令牌|(当前区域自动生成)
|
||||
[login.auth]
|
||||
uid =
|
||||
csrf =
|
||||
cookie =
|
||||
access_token =
|
||||
refresh_token =
|
||||
|
||||
#######################
|
||||
# 功能设置 #
|
||||
#######################
|
||||
|
||||
; 主站每日任务(每日登录、观看、投币、分享)
|
||||
[main_site]
|
||||
enable = true
|
||||
; 每日观看
|
||||
watch = true
|
||||
; 每日分享
|
||||
share = true
|
||||
; 每日视频投币|random(随机热门)/fixed(关注列表)|投币稿件数(每日任务最大5)
|
||||
add_coin = true
|
||||
add_coin_mode = random
|
||||
add_coin_num = 5
|
||||
|
||||
; 日常/周常礼物
|
||||
[daily_bag]
|
||||
enable = true
|
||||
|
||||
; 双端心跳
|
||||
[double_heart]
|
||||
enable = true
|
||||
|
||||
; 友爱社签到
|
||||
[love_club]
|
||||
enable = true
|
||||
|
||||
; 领取心跳礼物
|
||||
[gift_heart]
|
||||
enable = true
|
||||
|
||||
; 直播每日任务|每日签到|每日登录
|
||||
[daily_task]
|
||||
enable = true
|
||||
|
||||
; 直播箱子实物抽奖
|
||||
[live_box]
|
||||
enable = true
|
||||
|
||||
; 直播预约有奖|UP_UID|逗号分隔
|
||||
[live_reservation]
|
||||
enable = true
|
||||
vmids = 9617619
|
||||
|
||||
; 每日24个小心心|依赖加密心跳服务器
|
||||
[small_heart]
|
||||
enable = true
|
||||
|
||||
; 直播扭蛋活动抽奖|依赖加密心跳服务器
|
||||
[live_capsule]
|
||||
enable = true
|
||||
|
||||
; 点亮灰色勋章|100亲密度|每日或者只点亮灰色
|
||||
[polish_the_medal]
|
||||
enable = true
|
||||
everyday = false
|
||||
|
||||
; 主站九宫格抽奖活动助手
|
||||
[main_activity]
|
||||
enable = true
|
||||
|
||||
; 银瓜子兑换硬币
|
||||
[silver2coin]
|
||||
enable = true
|
||||
|
||||
; 直播大乱斗
|
||||
[live_pk]
|
||||
enable = false
|
||||
|
||||
; 直播舰长总督
|
||||
[live_guard]
|
||||
enable = false
|
||||
|
||||
; 直播其他礼物
|
||||
[live_gift]
|
||||
enable = false
|
||||
|
||||
; 直播节奏风暴|丢弃率(0-100)|尝试次数(范围值)
|
||||
[live_storm]
|
||||
enable = false
|
||||
drop_rate = 0
|
||||
attempt = "5,10"
|
||||
|
||||
; 直播天选时刻|抽取类型(0: 无限制; 1: 关注主播; 2: 粉丝勋章; 3大航海; 4用户等级;5主站等级)|自动取关(测试功能)依赖于award_record|过滤关键词|逗号分隔
|
||||
[live_anchor]
|
||||
enable = false
|
||||
limit_type = "0,1"
|
||||
auto_unfollow = true
|
||||
filter_words =
|
||||
|
||||
; 获取最新的中奖纪录
|
||||
[award_record]
|
||||
enable = true
|
||||
|
||||
; 活跃弹幕|弹幕房间(为空则随机)|弹幕内容(为空则随机)
|
||||
[barrage]
|
||||
enable = true
|
||||
room_id = 9522051
|
||||
content =
|
||||
|
||||
; 漫画助手
|
||||
[manga]
|
||||
enable = false
|
||||
|
||||
; 風機委員投票|需要实名认证|慎用
|
||||
[judgement]
|
||||
enable = false
|
||||
auto_apply = false
|
||||
|
||||
; 大会员权益|年度大会员专享
|
||||
[vip_privilege]
|
||||
enable = false
|
||||
|
||||
; B币券消费|年度大会员专享|每月默认充值数量5B币|消费方式优先级从上到下
|
||||
[bp_consumption]
|
||||
enable = false
|
||||
# 消费B币充电|充电的目标UID|可充值自己的UID
|
||||
bp2charge = false
|
||||
bp2charge_uid = 6580464
|
||||
# 消费B币充值金瓜子|5000金瓜子
|
||||
bp2gold = false
|
||||
|
||||
; 自动转发抽奖动态|自动取关未中奖动态|强制清除抽奖组关注|过滤低于多少粉丝|自定义回复|过滤词|逗号分割
|
||||
[dynamic]
|
||||
enable = false
|
||||
clear_dynamic = false
|
||||
clear_group_follow = false
|
||||
min_fans_num = 15000
|
||||
auto_reply_text =
|
||||
filter_words =
|
||||
|
||||
; 游戏赛事竞猜预测|破产机|每日竞猜次数|每次竞猜硬币(1-10)|下注(1.压大,2.压小,3.随机)
|
||||
[match_forecast]
|
||||
enable = false
|
||||
max_num = 20
|
||||
max_coin = 10
|
||||
bet = 1
|
||||
|
||||
; 休眠时间|时间区间(0-23)|逗号分隔
|
||||
[sleep]
|
||||
enable = true
|
||||
section = "2,3,4,5,6"
|
||||
|
||||
#######################
|
||||
# 通知设置 #
|
||||
#######################
|
||||
|
||||
; 消息推送|消息推送过滤词|逗号分割|优先级从上到下
|
||||
[notify]
|
||||
enable = false
|
||||
filter_words =
|
||||
|
||||
; Dingtalk机器人|token|依赖USE_NOTIFY
|
||||
[notify.dingtalk]
|
||||
token =
|
||||
|
||||
; Tele机器人|url(可选)|token|chatid|依赖USE_NOTIFY
|
||||
[notify.telegram]
|
||||
url =
|
||||
bottoken =
|
||||
chatid =
|
||||
|
||||
; Pushplus酱|token|依赖USE_NOTIFY
|
||||
[notify.pushplus]
|
||||
token =
|
||||
|
||||
; Sever酱(原版)|令牌Key|依赖USE_NOTIFY
|
||||
[notify.sc]
|
||||
sckey =
|
||||
|
||||
; Server酱(Turbo版)|令牌Key|依赖USE_NOTIFY
|
||||
[notify.sct]
|
||||
sctkey =
|
||||
|
||||
; GoCqhttp|url|token|目标qq|依赖USE_NOTIFY
|
||||
[notify.gocqhttp]
|
||||
url = ""
|
||||
token =
|
||||
target_qq =
|
||||
|
||||
; 飞书机器人|依赖USE_NOTIFY
|
||||
[notify.feishu]
|
||||
token =
|
||||
|
||||
; Debug|个人调试推送|url|token
|
||||
[notify.debug]
|
||||
url = ""
|
||||
token =
|
||||
|
||||
; 企业微信群机器人|token
|
||||
[notify.we_com]
|
||||
token =
|
||||
|
||||
; 企业微信应用消息|corp_id|corp_secret|agent_id|to_user
|
||||
[notify.we_com_app]
|
||||
corp_id =
|
||||
corp_secret =
|
||||
agent_id =
|
||||
to_user =
|
||||
|
||||
#######################
|
||||
# 基础设置 #
|
||||
#######################
|
||||
|
||||
; 独立推送服务(主)|主备冲突
|
||||
[alone_monitor]
|
||||
enable = false
|
||||
server_addr = "tcp://livecmt-1.mudew.com:10088"
|
||||
server_key = ""
|
||||
|
||||
; 分区推送服务(备)|主备冲突
|
||||
[zone_monitor]
|
||||
enable = true
|
||||
server_addr = "tcp://broadcastlv.chat.bilibili.com:2243/sub"
|
||||
|
||||
; 加密心跳服务器(开源)|如失效自行搭建
|
||||
[heartbeat_enc]
|
||||
server = "http://heartbeat-1.mudew.com:3000/enc"
|
||||
|
||||
#######################
|
||||
# 房间设置 #
|
||||
#######################
|
||||
|
||||
; 直播间ID,全局房间,用于礼物赠送、心跳等等.
|
||||
[global_room]
|
||||
room_id = 9522051
|
||||
|
||||
; 弹幕监控房间(为空则随机)
|
||||
[socket]
|
||||
room_id = 9522051
|
||||
|
||||
; 勋章亲密度,测试功能,有短位使用短位反之长位,左侧优先,仅支持辣条和亿元
|
||||
; 当列表中所有ID都已达到每日上限,剩余礼物赠送ROOM_ID指定的直播间
|
||||
; 是否填满(按时间投喂正常礼物,否则过期礼物)|直播间ID列表|逗号分隔|
|
||||
[intimacy]
|
||||
feed_fill = false
|
||||
room_list = 9522051
|
||||
|
||||
#######################
|
||||
# 网络设置 #
|
||||
#######################
|
||||
|
||||
; 验证SSL证书|请求时验证SSL证书行为
|
||||
[network.ssl]
|
||||
verify_ssl = true
|
||||
|
||||
; 是否使用代理|(http\https)
|
||||
[network.proxy]
|
||||
enable = false
|
||||
proxy = "http://127.0.0.1:8888"
|
||||
|
||||
#######################
|
||||
# 程序设置 #
|
||||
#######################
|
||||
|
||||
; 调试模式|采集完整日志
|
||||
[debug]
|
||||
enable = false
|
||||
|
||||
; 记录日志|日志回调地址
|
||||
[log]
|
||||
enable = false
|
||||
callback = "http://www.example.com/api.send?text={account}[{level}]: {message}"
|
||||
# 错误回调级别
|
||||
#
|
||||
# DEBUG 100
|
||||
# INFO 200
|
||||
# NOTICE 250
|
||||
# WARNING 300
|
||||
# ERROR 400
|
||||
#
|
||||
callback_level = 400
|
||||
|
||||
; app设置
|
||||
[print]
|
||||
; 用户名,可自定义
|
||||
uname =
|
||||
; 账号别名,如果为空则默认使用登录账号作为标示
|
||||
user_identity =
|
||||
; 多账号区别输出
|
||||
multiple = false
|
||||
@ -1,36 +0,0 @@
|
||||
{
|
||||
"remarks": "有需要可以自己添加,或者提pr",
|
||||
"data": [
|
||||
{
|
||||
"_url": "注释: 活动地址",
|
||||
"url": "https://www.bilibili.com/blackboard/activity-S9PC.html",
|
||||
"_title": "注释: 活动标题",
|
||||
"title": "vivo S9系列照亮我的美",
|
||||
"_description": "注释: 活动描述",
|
||||
"description": "vivo S9系列照亮我的美",
|
||||
"_sid": "注释: 活动SID",
|
||||
"sid": "f3ae9322-817d-11eb-8597-246e966235d8",
|
||||
"_login": "注释: 登录+1次机会",
|
||||
"login": "true",
|
||||
"_follow": "注释: 关注+1次机会",
|
||||
"follow": "false",
|
||||
"_share": "注释: 分享+1次机会",
|
||||
"share": "true",
|
||||
"_draw_times": "抽奖次数",
|
||||
"draw_times": 2,
|
||||
"_expire_at": "注释: 到期时间",
|
||||
"expire_at": "2021-03-30 23:59:59"
|
||||
},
|
||||
{
|
||||
"url": "https://www.bilibili.com/blackboard/activity-yellowVSgreen7th.html",
|
||||
"title": "哔哩哔哩,黄绿合战7th",
|
||||
"description": "神仙打架、大型选择困难症的噩梦!鬼畜区的巅峰对决,每日两两battle,为你带来最棒的视听盛宴!",
|
||||
"sid": "13096c11-e89a-11eb-8597-246e966235d8",
|
||||
"login": "true",
|
||||
"follow": "false",
|
||||
"share": "true",
|
||||
"draw_times": 1,
|
||||
"expire_at": "2021-08-12 11:59:59"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
{
|
||||
"pool": "https://api.live.bilibili.com/xlive/web-ucenter/v1/capsule/get_pool_detail?pool_id=131&_=1616829671726",
|
||||
"v3": "https://api.live.bilibili.com/xlive/web-ucenter/v1/capsule/get_capsule_info_v3?id=79&from=web&_=1608110093802",
|
||||
"remarks": "有需要可以自己添加,或者提pr",
|
||||
"data": [
|
||||
{
|
||||
"_url": "注释: 活动地址",
|
||||
"url": "https://www.bilibili.com/blackboard/activity-aEe0qbEc8N.html",
|
||||
"_title": "注释: 活动标题",
|
||||
"title": "原神2.2应援激励计划",
|
||||
"_description": "注释: 活动描述",
|
||||
"description": "每日在原神分区任意直播间观看,20分钟1张、1小时2张、2小时3张,每日最高6张。",
|
||||
"_room_id": "注释: 活动直播间,如果为0,则取分区随机一个",
|
||||
"room_id": 0,
|
||||
"_area_id": "注释: 子分区id",
|
||||
"area_id": 321,
|
||||
"_parent_area_id": "注释: 主分区id",
|
||||
"parent_area_id": 3,
|
||||
"_coin_id": "注释: 抽奖id",
|
||||
"coin_id": 284,
|
||||
"_pool_id": "注释: 抽奖id",
|
||||
"pool_id": 290,
|
||||
"_watch_time": "注释: 观看时长 单位秒",
|
||||
"watch_time": 7320,
|
||||
"_draw_times": "注释: 抽奖次数",
|
||||
"draw_times": 6,
|
||||
"_expire_at": "注释: 活动有效时间",
|
||||
"expire_at": "2021-11-23 23:59:59"
|
||||
},
|
||||
{
|
||||
"url": "https://live.bilibili.com/6",
|
||||
"title": "S11,LOL,英雄联盟,全球总决赛",
|
||||
"description": "每日在LOL直播间观看,1分钟1张,3分钟2张,5分钟3张",
|
||||
"room_id": 0,
|
||||
"area_id": 86,
|
||||
"parent_area_id": 2,
|
||||
"coin_id": 76,
|
||||
"watch_time": 600,
|
||||
"draw_times": 0,
|
||||
"expire_at": "2021-11-06 23:59:59"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"code": 0,
|
||||
"project": "BiliHelper-personal",
|
||||
"branch": "master",
|
||||
"source": "https://github.com/lkeme/BiliHelper-personal",
|
||||
"raw_url": "https://cdn.jsdelivr.net/gh/lkeme/BiliHelper-personal@master/data/latest_version.json",
|
||||
"purge_url": "https://purge.jsdelivr.net/gh/lkeme/BiliHelper-personal@master/data/latest_version.json",
|
||||
"version": "1.1.0.220218",
|
||||
"des": "程序有更新,请及时线上查看更新哦~",
|
||||
"time": "2022年2月18日10:40:35",
|
||||
"ini_version": "0.0.1",
|
||||
"ini_des": "配置有更新,请及时线上查看更新哦~",
|
||||
"ini_time": "2022年2月18日10:40:35"
|
||||
}
|
||||
@ -1,175 +0,0 @@
|
||||
{
|
||||
"DynamicForward": {
|
||||
"default": [
|
||||
"从未中奖,从未放弃[doge]",
|
||||
"来当分母= =",
|
||||
"让我中一次吧QAQ",
|
||||
"继续分母",
|
||||
"转发动态",
|
||||
"单纯想中次奖",
|
||||
"我我我",
|
||||
"不错",
|
||||
"来了来了",
|
||||
"爱了",
|
||||
"(;¬_¬)",
|
||||
"(~_~;)",
|
||||
"= =!",
|
||||
"╮(╯▽╰)╭",
|
||||
"(シ_ _)シ",
|
||||
">_<",
|
||||
"(๑• _ •๑)",
|
||||
"(:3_ヽ)_",
|
||||
"(⌒▽⌒)",
|
||||
"(`・ω・´)",
|
||||
"(◦˙▽˙◦)",
|
||||
"(=・ω・=)",
|
||||
"_Σ:з」∠)シ",
|
||||
"o(∩_∩)o",
|
||||
"(〜 ̄▽ ̄)〜",
|
||||
"(๑• ▽ •๑)",
|
||||
"哔哩哔哩干杯~",
|
||||
"Bilibili 干杯~",
|
||||
"bilibili 干杯~",
|
||||
"[doge][doge][doge]",
|
||||
"冲冲冲[打call][打call]",
|
||||
"[doge]",
|
||||
"万一可能呢",
|
||||
"我的",
|
||||
"[打call]",
|
||||
"就看欧不欧啦",
|
||||
"来了",
|
||||
"中",
|
||||
"好诶",
|
||||
"好耶",
|
||||
"拉低中奖率",
|
||||
"重在拉低中奖率[doge]",
|
||||
"分母",
|
||||
"评论",
|
||||
"成为一个分母,希望成为分子",
|
||||
"[藏狐]我来",
|
||||
"重在参与[OK]",
|
||||
"就是我[给心心][打call]",
|
||||
"抽起来!!!",
|
||||
"我也要中奖",
|
||||
"冲",
|
||||
"[拥抱]",
|
||||
"万一呢?",
|
||||
"我来了",
|
||||
"欧欧欧",
|
||||
"冲冲冲",
|
||||
"谢谢给我一个中奖的机会",
|
||||
"奖励不重要,重要的是心[doge]",
|
||||
"许愿",
|
||||
"分母报道",
|
||||
"大吉大利",
|
||||
"欧气满满",
|
||||
"不想再当分母",
|
||||
"吸欧气",
|
||||
"中!!!",
|
||||
"",
|
||||
"好运来",
|
||||
"啊~",
|
||||
"哈哈哈",
|
||||
"抽奖奖(⌒▽⌒)",
|
||||
"中奖绝缘体",
|
||||
"绝缘体",
|
||||
"求脱非入欧",
|
||||
"好运",
|
||||
"中奖绝缘体表示想中!",
|
||||
"呜呜呜非洲人来了",
|
||||
"选我吧",
|
||||
"一定会中",
|
||||
"好运bufff",
|
||||
"滴滴滴",
|
||||
"哇哇哇哇",
|
||||
"万一呢",
|
||||
"非酋日常",
|
||||
"加油",
|
||||
"抽中吧",
|
||||
"我要",
|
||||
"想欧一次!",
|
||||
"拉低中奖率233",
|
||||
"想要...",
|
||||
"路过拉低中奖率",
|
||||
"希望有个好运气",
|
||||
"中奖",
|
||||
"什么时候才会抽到我呢?",
|
||||
"试试水,看看能不能中",
|
||||
"过来水一手",
|
||||
"这辈子都不可能中奖的",
|
||||
"先拉低中奖率23333",
|
||||
"先抽奖,抽不到再说",
|
||||
"嘤嘤嘤",
|
||||
"捞一把",
|
||||
"我就想中一次",
|
||||
"拉低拉低",
|
||||
"试一试",
|
||||
"搞一搞",
|
||||
"中奖什么的不可能的( ̄▽ ̄)",
|
||||
"听说我中奖了?",
|
||||
"脱非转欧",
|
||||
"emm",
|
||||
"无聊.。。。。",
|
||||
"[星星眼]",
|
||||
"[妙啊]",
|
||||
"[辣眼睛]",
|
||||
"[吃瓜][吃瓜]",
|
||||
"[滑稽]",
|
||||
"[呲牙]",
|
||||
"[打call][打call]",
|
||||
"[哈欠][哈欠]",
|
||||
"[吃瓜]不嫌事大",
|
||||
"[口罩]",
|
||||
"[思考]",
|
||||
"[冷][冷][冷]",
|
||||
"次次参加",
|
||||
"从来没中过",
|
||||
"让我中吧",
|
||||
"来中个吧",
|
||||
"送妹子多好",
|
||||
"再送个小姐姐咋样",
|
||||
"忍不住抽",
|
||||
" (* ̄︶ ̄)",
|
||||
"如影随形",
|
||||
"参加够多就能中奖",
|
||||
"参加够多就能当分子",
|
||||
"[喜极而泣]",
|
||||
"我是天选之子",
|
||||
"中一次吧!",
|
||||
"坚持不懈,迎难而上,开拓创新!",
|
||||
"[OK][OK]",
|
||||
"抽个奖和寂寞",
|
||||
"中中",
|
||||
"坚持不懈,迎难而上!",
|
||||
"呵呵",
|
||||
"我一般不抽奖,除非忍不住。",
|
||||
"[OK]",
|
||||
"[喜欢]",
|
||||
"[偷笑]",
|
||||
"[笑]",
|
||||
"[吃瓜]",
|
||||
"[奋斗]",
|
||||
"在",
|
||||
"冲吖~",
|
||||
"[保佑][保佑]",
|
||||
"从未中,从未停",
|
||||
"[抠鼻][抠鼻]",
|
||||
"来力",
|
||||
"秋梨膏",
|
||||
"从不缺席",
|
||||
"分子",
|
||||
"1",
|
||||
"好",
|
||||
"rush",
|
||||
"来来来",
|
||||
"ok",
|
||||
"凑热闹",
|
||||
"我要我要[打call]",
|
||||
"我还能中!让我中!!!",
|
||||
"大家都散了吧,已经抽完了,是我的",
|
||||
"给我中一次吧!",
|
||||
"我来抽个奖",
|
||||
"[doge][doge][doge]"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
FROM php:alpine
|
||||
|
||||
#MAINTAINER zsnmwy <szlszl35622@gmail.com>
|
||||
LABEL AUTHOR = "Lkeme <Useri@live.cn>"
|
||||
|
||||
ENV USER_NAME='' \
|
||||
USER_PASSWORD='' \
|
||||
REPO_URL='https://github.com/' \
|
||||
CUSTOM_CLONE_URL='https://speed.example.com/example/example.git' \
|
||||
MIRRORS="0" \
|
||||
CONIFG_PATH='/app/conf/user.ini' \
|
||||
Green="\\033[32m" \
|
||||
Red="\\033[31m" \
|
||||
GreenBG="\\033[42;37m" \
|
||||
RedBG="\\033[41;37m" \
|
||||
Font="\\033[0m" \
|
||||
Green_font_prefix="\\033[32m" \
|
||||
Green_background_prefix="\\033[42;37m" \
|
||||
Font_color_suffix="\\033[0m" \
|
||||
Info="${Green}[信息]${Font}" \
|
||||
OK="${Green}[OK]${Font}" \
|
||||
Error="${Red}[错误]${Font}"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
||||
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||
RUN docker-php-ext-install sockets
|
||||
|
||||
#RUN if [ "${CN}" = true ]; then export REPO_URL="https://github.com.cnpmjs.org"; fi
|
||||
|
||||
#RUN set -ex \
|
||||
# && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
# && echo "Asia/Shanghai" > /etc/timezone \
|
||||
|
||||
RUN apk add --no-cache git && \
|
||||
git clone ${REPO_URL}/lkeme/BiliHelper-personal.git --depth=1 /app && \
|
||||
cp -f /app/docker/entrypoint.sh /usr/local/bin/entrypoint.sh && \
|
||||
chmod 777 /usr/local/bin/entrypoint.sh && \
|
||||
php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');" && \
|
||||
php composer-setup.php && \
|
||||
php composer.phar install && \
|
||||
rm -r /var/cache/apk && \
|
||||
rm -r /usr/share/man
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# 源切换
|
||||
case ${MIRRORS} in
|
||||
"custom")
|
||||
# custom
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-自定义克隆链接 ${Font} \n ======== \n"
|
||||
git remote set-url origin ${CUSTOM_CLONE_URL}
|
||||
;;
|
||||
"0")
|
||||
# https://github.com/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-github.com ${Font} \n ======== \n"
|
||||
git remote set-url origin https://github.com/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"1")
|
||||
# https://ghproxy.com/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-ghproxy.com ${Font} \n ======== \n"
|
||||
git remote set-url origin https://ghproxy.com/https://github.com/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"2")
|
||||
# http://fastgit.org/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-hub.fastgit.xyz ${Font} \n ======== \n"
|
||||
git remote set-url origin https://hub.fastgit.xyz/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"3")
|
||||
# https://hub.gitfast.tk/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-hub.gitfast.tk ${Font} \n ======== \n"
|
||||
git remote set-url origin https://hub.gitfast.tk/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"4")
|
||||
# https://hub.gitslow.tk/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-hub.gitslow.tk ${Font} \n ======== \n"
|
||||
git remote set-url origin https://hub.gitslow.tk/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"5")
|
||||
# https://hub.verge.tk/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-hub.verge.tk ${Font} \n ======== \n"
|
||||
git remote set-url origin https://hub.verge.tk/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
"6")
|
||||
# https://gh.api.99988866.xyz/
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-gh.api.99988866.xyz ${Font} \n ======== \n"
|
||||
git remote set-url origin https://gh.api.99988866.xyz/https://github.com/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
*)
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 切换源-github.com ${Font} \n ======== \n"
|
||||
git remote set-url origin https://github.com/lkeme/BiliHelper-personal.git
|
||||
;;
|
||||
esac
|
||||
|
||||
# 拉取更新
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 正使用 git pull 同步项目 ${Font} \n ======== \n"
|
||||
git pull
|
||||
|
||||
# 安装依赖
|
||||
echo -e "\n ======== \n ${Info} ${GreenBG} 安装/更新 项目运行依赖 ${Font} \n ======== \n"
|
||||
php composer.phar install
|
||||
echo -e "\n \n \n \n"
|
||||
|
||||
# 判断类型
|
||||
if [[ -f ${CONIFG_PATH} ]]; then
|
||||
echo -e "\n ======== \n ${GreenBG} 正在使用外部配置文件 ${Font} \n ======== \n"
|
||||
else
|
||||
echo -e "${OK} ${GreenBG} 正在使用传入的环境变量进行用户配置。\n 如果需要配置更多选择项,请通过挂载配置文件来传入。具体参考项目中的README。\n https://github.com/lkeme/BiliHelper-personal.git ${Font} \n ======== \n "
|
||||
cp /app/conf/user.ini.example /app/conf/user.ini
|
||||
sed -i ''"$(cat /app/conf/user.ini -n | grep "username = \"\"" | awk '{print $1}')"'c '"$(echo "username = \"${USER_NAME}\"")"'' ${CONIFG_PATH}
|
||||
sed -i ''"$(cat /app/conf/user.ini -n | grep "password = \"\"" | awk '{print $1}')"'c '"$(echo "password = \"${USER_PASSWORD}\"")"'' ${CONIFG_PATH}
|
||||
fi
|
||||
|
||||
php index.php
|
||||
16
phpunit.xml
Normal file
16
phpunit.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false"
|
||||
bootstrap="test/bootstrap.php" colors="false" convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="Php Library Test Suite">
|
||||
<directory>test/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
140
plugin/CheckUpdate/CheckUpdate.php
Normal file
140
plugin/CheckUpdate/CheckUpdate.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
use Bhp\Cache\Cache;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Notice\Notice;
|
||||
use Bhp\Plugin\BasePluginRW;
|
||||
use Bhp\Plugin\Plugin;
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\TimeLock\TimeLock;
|
||||
use Bhp\Util\Resource\Resource;
|
||||
|
||||
class CheckUpdate extends BasePluginRW
|
||||
{
|
||||
/**
|
||||
* 插件信息
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected ?array $info = [
|
||||
'hook' => __CLASS__, // hook
|
||||
'name' => 'CheckUpdate', // 插件名称
|
||||
'version' => '0.0.1', // 插件版本
|
||||
'desc' => '检查版本更新', // 插件描述
|
||||
'author' => 'Lkeme',// 作者
|
||||
'priority' => 1000, // 插件优先级
|
||||
'cycle' => '24(小时)', // 运行周期
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Plugin $plugin
|
||||
*/
|
||||
public function __construct(Plugin &$plugin)
|
||||
{
|
||||
//
|
||||
TimeLock::initTimeLock();
|
||||
//
|
||||
Cache::initCache();
|
||||
//
|
||||
Log::info('加载CheckUpdate插件');
|
||||
// $this::class
|
||||
$plugin->register($this, 'execute');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 执行
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
if (TimeLock::getTimes() > time()) return;
|
||||
//
|
||||
$this->_checkUpdate();
|
||||
//
|
||||
TimeLock::setTimes(24 * 60 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function _checkUpdate(): void
|
||||
{
|
||||
//
|
||||
Log::info('开始检查项目更新');
|
||||
// resource object
|
||||
$offline = $this->fetchOfflineVersion();
|
||||
//
|
||||
Log::info('拉取线上最新配置');
|
||||
// object
|
||||
$online = $this->fetchOnlineVersion();
|
||||
// 比较版本
|
||||
if ($this->compareVersion($offline->get('version'), $online->version)) {
|
||||
// TODO 完善消息 支持markdown
|
||||
$time = $online->time;
|
||||
$version = $online->version;
|
||||
$des = $online->des;
|
||||
$info = "请注意版本变动更新哦~\n\n版本号: $version\n\n更新日志: $des\n\n更新时间: $time\n\n";
|
||||
Log::notice($info);
|
||||
Notice::push('update', $info);
|
||||
} else {
|
||||
Log::info('程序已是最新版本');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 拉取本地版本
|
||||
* @return void
|
||||
*/
|
||||
protected function fetchOfflineVersion(): Resource
|
||||
{
|
||||
$this->loadResource('version.json', 'json');
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 拉取线上版本
|
||||
* @return object
|
||||
*/
|
||||
protected function fetchOnlineVersion(): object
|
||||
{
|
||||
$url = $this->resource->get('raw_url');
|
||||
$payload = [];
|
||||
return Request::getJson(false, 'other', $url, $payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 比较版本号
|
||||
* @param string $off
|
||||
* @param string $on
|
||||
* @return bool
|
||||
*/
|
||||
protected static function compareVersion(string $off, string $on): bool
|
||||
{
|
||||
// true 有更新 false 无更新
|
||||
return !($off == $on);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写系统路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePath(string $filename): string
|
||||
{
|
||||
return str_replace("\\", "/", APP_RESOURCES_PATH . $filename);
|
||||
}
|
||||
}
|
||||
604
plugin/Login/Login.php
Normal file
604
plugin/Login/Login.php
Normal file
@ -0,0 +1,604 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
use Bhp\Api\Passport\ApiCaptcha;
|
||||
use Bhp\Api\Passport\ApiOauth2;
|
||||
use Bhp\Api\PassportTv\ApiQrcode;
|
||||
use Bhp\Cache\Cache;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Plugin\BasePlugin;
|
||||
use Bhp\Plugin\Plugin;
|
||||
use Bhp\TimeLock\TimeLock;
|
||||
use Bhp\User\User;
|
||||
use Bhp\Util\Common\Common;
|
||||
use Bhp\Util\Qrcode\Qrcode;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
|
||||
class Login extends BasePlugin
|
||||
{
|
||||
/**
|
||||
* 插件信息
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected ?array $info = [
|
||||
'hook' => __CLASS__, // hook
|
||||
'name' => 'Login', // 插件名称
|
||||
'version' => '0.0.1', // 插件版本
|
||||
'desc' => '登录模块', // 插件描述
|
||||
'author' => 'Lkeme',// 作者
|
||||
'priority' => 1001, // 插件优先级
|
||||
'cycle' => '24(小时)', // 运行周期
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $username = '';
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $password = '';
|
||||
|
||||
/**
|
||||
* @param Plugin $plugin
|
||||
*/
|
||||
public function __construct(Plugin &$plugin)
|
||||
{
|
||||
//
|
||||
TimeLock::initTimeLock();
|
||||
//
|
||||
Cache::initCache();
|
||||
//
|
||||
Log::info('加载Login插件');
|
||||
// $this::class
|
||||
$plugin->register($this, 'execute');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
//
|
||||
if (TimeLock::getTimes() && TimeLock::getTimes() < time()) {
|
||||
TimeLock::setTimes(7200);
|
||||
$this->keepLogin();
|
||||
}
|
||||
//
|
||||
if (!TimeLock::getTimes()) {
|
||||
$this->initLogin();
|
||||
TimeLock::setTimes(3600);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化登录
|
||||
* @return void
|
||||
*/
|
||||
protected function initLogin(): void
|
||||
{
|
||||
//
|
||||
$token = getU('access_token');
|
||||
$r_token = getU('refresh_token');
|
||||
// Token不存在的情况\直接调用登录
|
||||
Log::info('启动登录程序');
|
||||
if (!$token || !$r_token) {
|
||||
Log::info('准备载入登录令牌');
|
||||
$this->login();
|
||||
}
|
||||
// Token存在\校验有效性\否则调用登录
|
||||
Log::info('检查登录令牌有效性');
|
||||
if (!$this->validateToken($token)) {
|
||||
Log::warning('登录令牌失效或即将过期');
|
||||
Log::info('申请更换登录令牌中');
|
||||
if (!$this->refreshToken($token, $r_token)) {
|
||||
Log::warning('无效的登录令牌,尝试重新申请');
|
||||
$this->login();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 登录控制中心
|
||||
* @return void
|
||||
*/
|
||||
protected function login(): void
|
||||
{
|
||||
$this->checkLogin();
|
||||
//
|
||||
switch (getConf('login_mode.mode')) {
|
||||
case 1:
|
||||
// 账密模式
|
||||
$this->accountLogin();
|
||||
break;
|
||||
case 2:
|
||||
// 短信验证码模式
|
||||
$this->smsLogin();
|
||||
break;
|
||||
case 3:
|
||||
// 二维码模式
|
||||
$this->qrcodeLogin();
|
||||
break;
|
||||
case 4:
|
||||
// 行为验证码模式(暂未开放)
|
||||
// self::captchaLogin();
|
||||
failExit('此登录模式暂未开放');
|
||||
default:
|
||||
failExit('登录模式配置错误');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 保持认证
|
||||
* @return bool
|
||||
*/
|
||||
protected function keepLogin(): bool
|
||||
{
|
||||
//
|
||||
$token = getU('access_token');
|
||||
$r_token = getU('refresh_token');
|
||||
//
|
||||
if ($this->validateToken($token)) {
|
||||
return true;
|
||||
}
|
||||
Log::warning('令牌即将过期');
|
||||
Log::info('申请更换令牌中...');
|
||||
if (!$this->refreshToken($token, $r_token)) {
|
||||
Log::warning('无效令牌,正在重新申请...');
|
||||
self::accountLogin();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 校验令牌信息
|
||||
* @param string $token
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateToken(string $token): bool
|
||||
{
|
||||
// {"ts":1234,"code":0,"data":{"mid":1234,"access_token":"1234","expires_in":7759292}}
|
||||
$response = ApiOauth2::tokenInfo($token);
|
||||
//
|
||||
if (isset($response['code']) && $response['code']) {
|
||||
Log::error('检查令牌失败', ['msg' => $response['message']]);
|
||||
return false;
|
||||
}
|
||||
Log::notice('令牌有效期: ' . date('Y-m-d H:i:s', $response['ts'] + $response['data']['expires_in']));
|
||||
return $response['data']['expires_in'] > 14400;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 刷新token
|
||||
* @param string $token
|
||||
* @param string $r_token
|
||||
* @return bool
|
||||
*/
|
||||
protected function refreshToken(string $token, string $r_token): bool
|
||||
{
|
||||
$response = ApiOauth2::tokenRefresh($token, $r_token);
|
||||
// {"message":"user not login","ts":1593111694,"code":-101}
|
||||
if (isset($response['code']) && $response['code']) {
|
||||
Log::error('重新生成令牌失败', ['msg' => $response['message']]);
|
||||
return false;
|
||||
}
|
||||
Log::info('重新令牌生成完毕');
|
||||
$this->updateLoginInfo($response);
|
||||
Log::info('重置信息配置完毕');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 更新登录信息
|
||||
* @param array $data
|
||||
*/
|
||||
protected function updateLoginInfo(array $data): void
|
||||
{
|
||||
//
|
||||
$access_token = $data['data']['token_info']['access_token'];
|
||||
$this->updateInfo('access_token', $access_token);
|
||||
//
|
||||
$refresh_token = $data['data']['token_info']['refresh_token'];
|
||||
$this->updateInfo('refresh_token', $refresh_token);
|
||||
//
|
||||
$cookie = $this->formatCookie($data['data']['cookie_info']['cookies']);
|
||||
$this->updateInfo('cookie', $cookie);
|
||||
//
|
||||
$user = User::parseCookie();
|
||||
$this->updateInfo('uid', $user['uid'], false);
|
||||
$this->updateInfo('csrf', $user['csrf'], false);
|
||||
$this->updateInfo('sid', $user['sid'], false);
|
||||
//
|
||||
// $this->updateInfo('username',$this->username);
|
||||
// $this->updateInfo('password',$this->password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 更新Tv登录信息
|
||||
* @param array $data
|
||||
*/
|
||||
protected function updateTvLoginInfo(array $data): void
|
||||
{
|
||||
//
|
||||
$access_token = $data['data']['access_token'];
|
||||
$this->updateInfo('access_token', $access_token);
|
||||
//
|
||||
$refresh_token = $data['data']['refresh_token'];
|
||||
$this->updateInfo('refresh_token', $refresh_token);
|
||||
//
|
||||
//
|
||||
$cookie = $this->token2Cookie($access_token);
|
||||
$this->updateInfo('cookie', $cookie);
|
||||
//
|
||||
$user = User::parseCookie();
|
||||
$this->updateInfo('uid', $user['uid'], false);
|
||||
$this->updateInfo('csrf', $user['csrf'], false);
|
||||
$this->updateInfo('sid', $user['sid'], false);
|
||||
//
|
||||
// $this->updateInfo('username',$this->username);
|
||||
// $this->updateInfo('password',$this->password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 更新信息
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param bool $print
|
||||
* @param bool $hide
|
||||
* @return void
|
||||
*/
|
||||
protected function updateInfo(string $key, mixed $value, bool $print = true, bool $hide = true): void
|
||||
{
|
||||
setU($key, $value);
|
||||
if ($print) {
|
||||
Log::info(" > $key: " . ($hide ? Common::replaceStar($value, 6, 6) : $value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 格式化Cookie
|
||||
* @param array $cookies
|
||||
* @return string
|
||||
*/
|
||||
protected function formatCookie(array $cookies): string
|
||||
{
|
||||
$c = '';
|
||||
foreach ($cookies as $cookie) {
|
||||
$c .= $cookie['name'] . '=' . $cookie['value'] . ';';
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 账密登录
|
||||
* @param string $validate
|
||||
* @param string $challenge
|
||||
* @param string $mode
|
||||
* @return void
|
||||
*/
|
||||
protected function accountLogin(string $validate = '', string $challenge = '', string $mode = '账密模式'): void
|
||||
{
|
||||
Log::info("尝试 $mode 登录");
|
||||
// {"ts":1593079322,"code":-629,"message":"账号或者密码错误"}
|
||||
// {"ts":1593082268,"code":-105,"data":{"url":"https://passport.bilibili.com/register/verification.html?success=1>=b6e5b7fad7ecd37f465838689732e788&challenge=7efb4020b22c0a9ac124aea624e11ad7&ct=1&hash=7fa8282ad93047a4d6fe6111c93b308a"},"message":"验证码错误"}
|
||||
// {"ts":1593082432,"code":0,"data":{"status":0,"token_info":{"mid":123456,"access_token":"123123","refresh_token":"123123","expires_in":2592000},"cookie_info":{"cookies":[{"name":"bili_jct","value":"123123","http_only":0,"expires":1595674432},{"name":"DedeUserID","value":"123456","http_only":0,"expires":1595674432},{"name":"DedeUserID__ckMd5","value":"123123","http_only":0,"expires":1595674432},{"name":"sid","value":"bd6aagp7","http_only":0,"expires":1595674432},{"name":"SESSDATA","value":"6d74d850%123%2Cf0e36b61","http_only":1,"expires":1595674432}],"domains":[".bilibili.com",".biligame.com",".bigfunapp.cn"]},"sso":["https://passport.bilibili.com/api/v2/sso","https://passport.biligame.com/api/v2/sso","https://passport.bigfunapp.cn/api/v2/sso"]}}
|
||||
// {"ts":1610254019,"code":0,"data":{"status":2,"url":"https://passport.bilibili.com/account/mobile/security/managephone/phone/verify?tmp_token=2bc5dd260df7158xx860565fxx0d5311&requestId=dffcfxx052fe11xxa9c8e2667739c15c&source=risk","message":"您的账号存在高危异常行为,为了您的账号安全,请验证手机号后登录帐号"}}
|
||||
// https://passport.bilibili.com/mobile/verifytel_h5.html
|
||||
$response = ApiQrcode::passwordLogin($this->username, $this->password, $validate, $challenge);
|
||||
//
|
||||
$this->loginAfter($mode, $response['code'], $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 短信登录
|
||||
* @param string $mode
|
||||
* @return void
|
||||
*/
|
||||
protected function smsLogin(string $mode = '短信模式'): void
|
||||
{
|
||||
Log::info("尝试 $mode 登录");
|
||||
//
|
||||
if (getConf('login_check.phone')) {
|
||||
if (!Common::checkPhone($this->username)) {
|
||||
failExit('当前用户名不是有效手机号格式');
|
||||
}
|
||||
}
|
||||
//
|
||||
$captcha = $this->sendSms($this->username, getConf('login_country.code'));
|
||||
$code = $this->cliInput('请输入收到的短信验证码: ');
|
||||
$response = ApiQrcode::smsLogin($captcha, $code);
|
||||
//
|
||||
$this->loginAfter($mode, $response['code'], $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 扫码登录
|
||||
* @param string $mode
|
||||
* @return void
|
||||
*/
|
||||
protected function qrcodeLogin(string $mode = '扫码模式'): void
|
||||
{
|
||||
Log::info("尝试 $mode 登录");
|
||||
//
|
||||
$this->cliInput("请尝试放大窗口,以确保二维码完整显示,回车继续");
|
||||
//
|
||||
$response = $this->fetchQrAuthCode();
|
||||
$auth_code = $response['auth_code'];
|
||||
//
|
||||
Qrcode::show($response['url']);
|
||||
// max 180 step 3
|
||||
foreach (range(0, 180, 3) as $_) {
|
||||
sleep(3);
|
||||
if ($this->validateQrAuthCode($auth_code)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
failExit("扫码失败 二维码已失效");
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取AuthCode
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchQrAuthCode(): array
|
||||
{
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"url":"https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/auth?auth_code=xxxx","auth_code":"xxxx"}}
|
||||
$response = ApiQrcode::authCode();
|
||||
//
|
||||
if ($response['code']) {
|
||||
failExit('获取AuthCode错误', ['msg' => $response['message']]);
|
||||
}
|
||||
Log::info("获取到AuthCode: {$response['data']['auth_code']}");
|
||||
return $response['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 验证AuthCode
|
||||
* @param string $auth_code
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateQrAuthCode(string $auth_code): bool
|
||||
{
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"mid":123,"access_token":"xxx","refresh_token":"xxx","expires_in":2592000}}
|
||||
$response = ApiQrcode::poll($auth_code);
|
||||
echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
switch ($response['code']) {
|
||||
case 0:
|
||||
// 登录成功
|
||||
Log::notice("扫码成功 {$response['message']}");
|
||||
//
|
||||
// $this->updateTvLoginInfo($response);
|
||||
$this->updateLoginInfo($response);
|
||||
return true;
|
||||
case -3:
|
||||
// API校验密匙错误
|
||||
failExit("扫码失败 {$response['message']}");
|
||||
case -400:
|
||||
// 请求错误
|
||||
failExit("扫码失败 {$response['message']}");
|
||||
case 86038:
|
||||
// 二维码已失效
|
||||
failExit("扫码失败 {$response['message']}");
|
||||
case 86039:
|
||||
// 二维码尚未确认
|
||||
Log::info("等待扫码 {$response['message']}");
|
||||
return false;
|
||||
default:
|
||||
failExit("扫码失败 {$response['message']}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 登录后处理
|
||||
* @param string $mode
|
||||
* @param int $code
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function loginAfter(string $mode, int $code, array $data): void
|
||||
{
|
||||
switch ($code) {
|
||||
case 0:
|
||||
// data->data->status number
|
||||
if (array_key_exists('status', $data['data'])) {
|
||||
// 二次判断
|
||||
switch ($data['data']['status']) {
|
||||
case 0:
|
||||
// 正常登录
|
||||
$this->loginSuccess($mode, $data);
|
||||
break;
|
||||
case 2:
|
||||
// 异常高危
|
||||
$this->loginFail($mode, $data['data']['message']);
|
||||
case 3:
|
||||
// 需要验证手机号
|
||||
$this->loginFail($mode, "需要验证手机号: {$data['data']['url']}");
|
||||
default:
|
||||
// 未知错误
|
||||
$this->loginFail($mode, '未知错误: ' . json_encode($data));
|
||||
}
|
||||
} else {
|
||||
// 正常登录
|
||||
$this->loginSuccess($mode, $data);
|
||||
}
|
||||
break;
|
||||
case -105:
|
||||
// 需要验证码
|
||||
$this->loginFail($mode, '此次登录需要验证码或' . $data['message']);
|
||||
case -629:
|
||||
// 密码错误
|
||||
$this->loginFail($mode, $data['message']);
|
||||
case -2100:
|
||||
// 验证手机号
|
||||
$this->loginFail($mode, '账号启用了设备锁或异地登录需验证手机号');
|
||||
default:
|
||||
// 未知错误
|
||||
$this->loginFail($mode, '未知错误: ' . $data['message']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 登录成功处理
|
||||
* @param string $mode
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function loginSuccess(string $mode, array $data): void
|
||||
{
|
||||
Log::info("$mode 登录成功");
|
||||
$this->updateLoginInfo($data);
|
||||
Log::info('生成信息配置完毕');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 登录失败处理
|
||||
* @param string $mode
|
||||
* @param string $data
|
||||
* @return void
|
||||
*/
|
||||
#[NoReturn]
|
||||
protected function loginFail(string $mode, string $data): void
|
||||
{
|
||||
failExit("$mode 登录失败", ['msg' => $data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查登录
|
||||
*/
|
||||
protected function checkLogin(): void
|
||||
{
|
||||
$username = getConf('login_account.username');
|
||||
$password = getConf('login_account.password');
|
||||
if (empty($username) || empty($password)) {
|
||||
failExit('空白的帐号和口令');
|
||||
}
|
||||
$this->username = $username;
|
||||
$this->password = $this->publicKeyEnc($password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 公钥加密
|
||||
* @param string $plaintext
|
||||
* @return string
|
||||
*/
|
||||
protected function publicKeyEnc(string $plaintext): string
|
||||
{
|
||||
Log::info('正在载入公钥');
|
||||
//
|
||||
$response = ApiOauth2::getKey();
|
||||
//
|
||||
if (isset($response['code']) && $response['code']) {
|
||||
failExit('公钥载入失败', ['msg' => $response['message']]);
|
||||
} else {
|
||||
Log::info('公钥载入完毕');
|
||||
}
|
||||
// print_r($data);
|
||||
$public_key = $response['data']['key'];
|
||||
$hash = $response['data']['hash'];
|
||||
openssl_public_encrypt($hash . $plaintext, $crypt, $public_key);
|
||||
return base64_encode($crypt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 发送短信验证码
|
||||
* @param string $phone
|
||||
* @param string $cid
|
||||
* @return array
|
||||
*/
|
||||
protected function sendSms(string $phone, string $cid): array
|
||||
{
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"is_new":false,"captcha_key":"4e292933816755442c1568e2043b8e41","recaptcha_url":""}}
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"is_new":false,"captcha_key":"","recaptcha_url":"https://www.bilibili.com/h5/project-msg-auth/verify?ct=geetest\u0026recaptcha_token=ad520c3a4a3c46e29b1974d85efd2c4b\u0026gee_gt=1c0ea7c7d47d8126dda19ee3431a5f38\u0026gee_challenge=c772673050dce482b9f63ff45b681ceb\u0026hash=ea2850a43cc6b4f1f7b925d601098e5e"}}
|
||||
$raw = ApiQrcode::sendSms($phone, $cid);
|
||||
$response = json_decode($raw, true);
|
||||
//
|
||||
if ($response['code'] == 0 && isset($response['data']['captcha_key']) && $response['data']['recaptcha_url'] == '') {
|
||||
Log::info("短信验证码发送成功 {$response['data']['captcha_key']}");
|
||||
$payload['captcha_key'] = $response['data']['captcha_key'];
|
||||
return $payload;
|
||||
}
|
||||
failExit("短信验证码发送失败 $raw");
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 输入短信验证码
|
||||
* @param string $msg
|
||||
* @param int $max_char
|
||||
* @return string
|
||||
*/
|
||||
protected function cliInput(string $msg, int $max_char = 100): string
|
||||
{
|
||||
$stdin = fopen('php://stdin', 'r');
|
||||
echo '# ' . $msg;
|
||||
$input = fread($stdin, $max_char);
|
||||
fclose($stdin);
|
||||
return str_replace(PHP_EOL, '', $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取验证码
|
||||
* @return array
|
||||
*/
|
||||
protected function getCaptcha(): array
|
||||
{
|
||||
$response = ApiCaptcha::combine();
|
||||
Log::info('正在获取验证码 ' . $response['code']);
|
||||
if ($response['code'] == 0 && isset($response['data']['result'])) {
|
||||
return [
|
||||
'gt' => $response['data']['result']['gt'],
|
||||
'challenge' => $response['data']['result']['challenge'],
|
||||
'key' => $response['data']['result']['key'],
|
||||
];
|
||||
}
|
||||
return [
|
||||
'gt' => '',
|
||||
'challenge' => '',
|
||||
'key' => ''
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 验证码模式
|
||||
* @param string $mode
|
||||
* @return void
|
||||
*/
|
||||
protected function captchaLogin(string $mode = '验证码模式'): void
|
||||
{
|
||||
// $captcha_ori = $this->getCaptcha();
|
||||
// $captcha = $this->ocrCaptcha($captcha_ori);
|
||||
// $this->accountLogin($captcha['validate'], $captcha['challenge'], $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 转换Cookie
|
||||
* @param string $token
|
||||
* @return string
|
||||
*/
|
||||
protected function token2Cookie(string $token): string
|
||||
{
|
||||
$response = ApiOauth2::token2Cookie($token);
|
||||
$headers = $response['Set-Cookie'];
|
||||
$cookies = [];
|
||||
foreach ($headers as $header) {
|
||||
preg_match_all('/^(.*);/iU', $header, $cookie);
|
||||
$cookies[] = $cookie[0][0];
|
||||
}
|
||||
return implode("", array_reverse($cookies));
|
||||
}
|
||||
|
||||
}
|
||||
123
profile/example/config/user.ini
Normal file
123
profile/example/config/user.ini
Normal file
@ -0,0 +1,123 @@
|
||||
version = 0.0.1
|
||||
|
||||
#######################
|
||||
# 账户设置 #
|
||||
#######################
|
||||
|
||||
; 帐号/密码
|
||||
[login_account]
|
||||
username =
|
||||
password =
|
||||
|
||||
; 登录模式/[1.账密模式 2.短信验证码模式 3.扫码模式 4.行为验证码模式(暂未开放)]
|
||||
[login_mode]
|
||||
mode = 1
|
||||
|
||||
; 国家代码/mode=2触发/例:大陆86 澳大利亚61
|
||||
[login_country]
|
||||
code = 86
|
||||
|
||||
; 校验/mode=2触发/校验国内手机号/国外手机号关闭校验
|
||||
[login_check]
|
||||
phone = true
|
||||
|
||||
#######################
|
||||
# 通知设置 #
|
||||
#######################
|
||||
|
||||
; 消息推送/消息推送过滤词/逗号分割/优先级从上到下
|
||||
[notify]
|
||||
enable = false
|
||||
filter_words = test,测试
|
||||
|
||||
; Dingtalk机器人/token/依赖USE_NOTIFY
|
||||
[notify_dingtalk]
|
||||
token =
|
||||
|
||||
; Tele机器人/url(可选)/token/chatid/依赖USE_NOTIFY
|
||||
[notify_telegram]
|
||||
url =
|
||||
bottoken =
|
||||
chatid =
|
||||
|
||||
; Pushplus酱/token/依赖USE_NOTIFY
|
||||
[notify_pushplus]
|
||||
token =
|
||||
|
||||
; Sever酱(原版)/令牌Key/依赖USE_NOTIFY
|
||||
[notify_sc]
|
||||
sckey =
|
||||
|
||||
; Server酱(Turbo版)/令牌Key/依赖USE_NOTIFY
|
||||
[notify_sct]
|
||||
sctkey =
|
||||
|
||||
; GoCqhttp/url/token/目标qq/依赖USE_NOTIFY
|
||||
[notify_gocqhttp]
|
||||
url = ""
|
||||
token =
|
||||
target_qq =
|
||||
|
||||
; 飞书机器人/依赖USE_NOTIFY
|
||||
[notify_feishu]
|
||||
token =
|
||||
|
||||
; Debug/个人调试推送/url/token
|
||||
[notify_debug]
|
||||
url = ""
|
||||
token =
|
||||
|
||||
; 企业微信群机器人/token
|
||||
[notify_we_com]
|
||||
token =
|
||||
|
||||
; 企业微信应用消息/corp_id/corp_secret/agent_id/to_user
|
||||
[notify_we_com_app]
|
||||
corp_id =
|
||||
corp_secret =
|
||||
agent_id =
|
||||
to_user =
|
||||
|
||||
#######################
|
||||
# 网络设置 #
|
||||
#######################
|
||||
|
||||
; 验证SSL证书/请求时验证SSL证书行为
|
||||
[network_ssl]
|
||||
verify = true
|
||||
|
||||
; 是否使用代理/(http\https)
|
||||
[network_proxy]
|
||||
enable = false
|
||||
proxy = "http://127.0.0.1:8888"
|
||||
|
||||
#######################
|
||||
# 程序设置 #
|
||||
#######################
|
||||
|
||||
; 调试模式/采集完整日志
|
||||
[debug]
|
||||
enable = false
|
||||
|
||||
; 记录日志/日志回调地址
|
||||
[log]
|
||||
enable = false
|
||||
callback = "http://www.example.com/api.send?text={account}[{level}]: {message}"
|
||||
# 错误回调级别
|
||||
#
|
||||
# DEBUG 100
|
||||
# INFO 200
|
||||
# NOTICE 250
|
||||
# WARNING 300
|
||||
# ERROR 400
|
||||
#
|
||||
callback_level = 400
|
||||
|
||||
; app设置
|
||||
[print]
|
||||
; 用户名,可自定义
|
||||
uname =
|
||||
; 账号别名,如果为空则默认使用登录账号作为标示
|
||||
user_identity =
|
||||
; 多账号区别输出
|
||||
multiple = false
|
||||
34
profile/example/device/device.yaml
Normal file
34
profile/example/device/device.yaml
Normal file
@ -0,0 +1,34 @@
|
||||
device_version: 0.0.1
|
||||
|
||||
app:
|
||||
bili_a: # Android
|
||||
package: "tv.danmaku.bili"
|
||||
version: "6.72.0"
|
||||
build: "6720300"
|
||||
channel: "bili"
|
||||
device: "phone"
|
||||
mobi_app: "android"
|
||||
platform: "android"
|
||||
s_locale: "zh-Hans_CN"
|
||||
c_locale: "zh-Hans_CH"
|
||||
app_key: "MWQ4YjZlN2Q0NTIzMzQzNg=="
|
||||
secret_key: "NTYwYzUyY2NkMjg4ZmVkMDQ1ODU5ZWQxOGJmZmQ5NzM"
|
||||
app_key_n: "NzgzYmJiNzI2NDQ1MWQ4Mg=="
|
||||
secret_key_n: "MjY1MzU4M2M4ODczZGVhMjY4YWI5Mzg2OTE4YjFkNjU="
|
||||
bili_i: # IOS
|
||||
app_key: "MjdlYjUzZmM5MDU4ZjhjMw=="
|
||||
secret_key: "YzJlZDUzYTc0ZWVlZmUzY2Y5OWZiZDAxZDhjOWMzNzU="
|
||||
bili_t: # Tv
|
||||
app_key: "NDQwOWUyY2U4ZmZkMTJiOA=="
|
||||
secret_key: "NTliNDNlMDRhZDY5NjVmMzQzMTkwNjJiNDc4ZjgzZGQ="
|
||||
|
||||
platform:
|
||||
system:
|
||||
os: "android"
|
||||
os_ver: "7.1.2"
|
||||
model: "MuMu"
|
||||
network: "2" # 1 流量 2 WIFI
|
||||
headers:
|
||||
other_ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
|
||||
pc_ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"
|
||||
app_ua: "Mozilla/5.0 BiliDroid/${app.bili_a.version} (bbcallen@gmail.com) os/${platform.system.os} model/${device.model} mobi_app/${app.bili_a.mobi_app}build/${app.bili_a.build} channel/${app.bili_a.channel} innerVer/${app.bili_a.build}osVer/${platform.system.os_ver} network/${platform.system.network}"
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"code": 200,
|
||||
"MaterialObject": {
|
||||
"sensitive": [
|
||||
"测试",
|
||||
14
resources/version.json
Normal file
14
resources/version.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"code": 200,
|
||||
"project": "BiliHelper-personal",
|
||||
"branch": "master",
|
||||
"source": "https://github.com/lkeme/BiliHelper-personal",
|
||||
"raw_url": "https://gh.notifyplus.cf/https://raw.githubusercontent.com/lkeme/BiliHelper-personal/master/data/latest_version.json",
|
||||
"purge_url": "https://cdn.staticaly.com/gh/lkeme/BiliHelper-personal/master/data/latest_version.json",
|
||||
"version": "1.2.0.220517-dev",
|
||||
"des": "程序有更新,请及时线上查看更新哦~",
|
||||
"time": "2022年5月17日",
|
||||
"ini_version": "0.0.1",
|
||||
"ini_des": "配置有更新,请及时线上查看更新哦~",
|
||||
"ini_time": "2022年5月17日"
|
||||
}
|
||||
60
src/Api/Passport/ApiCaptcha.php
Normal file
60
src/Api/Passport/ApiCaptcha.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Api\Passport;
|
||||
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Sign\Sign;
|
||||
|
||||
class ApiCaptcha
|
||||
{
|
||||
/**
|
||||
* @use 获取验证码
|
||||
* @param int $plat
|
||||
* @return mixed
|
||||
*/
|
||||
public static function combine(int $plat = 3): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/web/captcha/combine';
|
||||
$payload = [
|
||||
'plat' => $plat
|
||||
];
|
||||
// {"code":0,"data":{"result":{"success":1,"gt":"b6e5b7fad7ecd37f465838689732e788","challenge":"88148a764f94e5923564b356a69277fc","key":"230509df5ce048ca9bf29e1ee323af30"},"type":1}}
|
||||
|
||||
return Request::getJson(true, 'other', $url, $payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 识别验证码
|
||||
* @param array $captcha
|
||||
* @return array
|
||||
*/
|
||||
public static function ocr(array $captcha):array{
|
||||
$url = 'https://captcha-v1.mudew.com:19951/';
|
||||
$payload = [
|
||||
'type' => 'gt3',
|
||||
'gt' => $captcha['gt'],
|
||||
"challenge" => $captcha['challenge'],
|
||||
"referer" => "https://passport.bilibili.com/"
|
||||
];
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
return Request::postJson(true,'other', $url, $payload, $headers);
|
||||
}
|
||||
}
|
||||
|
||||
91
src/Api/Passport/ApiLogin.php
Normal file
91
src/Api/Passport/ApiLogin.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Api\Passport;
|
||||
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Sign\Sign;
|
||||
|
||||
class ApiLogin
|
||||
{
|
||||
/**
|
||||
* @use 密码登录
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $validate
|
||||
* @param string $challenge
|
||||
* @return array
|
||||
*/
|
||||
public static function passwordLogin(string $username, string $password, string $validate = '', string $challenge = ''): array
|
||||
{
|
||||
// $url = 'https://passport.bilibili.com/api/v3/oauth2/login';
|
||||
$url = 'https://passport.bilibili.com/x/passport-login/oauth2/login';
|
||||
$payload = [
|
||||
'seccode' => $validate ? "$validate|jordan" : '',
|
||||
'validate' => $validate,
|
||||
'challenge' => $challenge,
|
||||
'permission' => 'ALL',
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'captcha' => '',
|
||||
'subid' => 1,
|
||||
'cookies' => ''
|
||||
];
|
||||
return Request::postJson(true, 'app', $url, Sign::login($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 发送短信验证码
|
||||
* @param string $phone
|
||||
* @param string $cid
|
||||
* @return string
|
||||
*/
|
||||
public static function sendSms(string $phone, string $cid): string
|
||||
{
|
||||
$url = 'https://passport.bilibili.com//x/passport-login/sms/send';
|
||||
// TODO 动态版本参数
|
||||
$payload = [
|
||||
'cid' => $cid,
|
||||
'tel' => $phone,
|
||||
'statistics' => '{"appId":1,"platform":3,"version":"6.72.0","abtest":""}',
|
||||
];
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"is_new":false,"captcha_key":"4e292933816755442c1568e2043b8e41","recaptcha_url":""}}
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"is_new":false,"captcha_key":"","recaptcha_url":"https://www.bilibili.com/h5/project-msg-auth/verify?ct=geetest\u0026recaptcha_token=ad520c3a4a3c46e29b1974d85efd2c4b\u0026gee_gt=1c0ea7c7d47d8126dda19ee3431a5f38\u0026gee_challenge=c772673050dce482b9f63ff45b681ceb\u0026hash=ea2850a43cc6b4f1f7b925d601098e5e"}}
|
||||
return Request::post('app', $url, Sign::login($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 短信验证码登录
|
||||
* @param array $captcha
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public static function smsLogin(array $captcha, string $code): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/x/passport-login/login/sms';
|
||||
$payload = [
|
||||
'captcha_key' => $captcha['captcha_key'],
|
||||
'cid' => $captcha['cid'],
|
||||
'tel' => $captcha['tel'],
|
||||
'statistics' => $captcha['statistics'],
|
||||
'code' => $code,
|
||||
];
|
||||
return Request::postJson(true, 'app', $url, Sign::login($payload));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
118
src/Api/Passport/ApiOauth2.php
Normal file
118
src/Api/Passport/ApiOauth2.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Api\Passport;
|
||||
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Sign\Sign;
|
||||
|
||||
class ApiOauth2
|
||||
{
|
||||
/**
|
||||
* 获取令牌信息
|
||||
* @param string $token
|
||||
* @return array
|
||||
*/
|
||||
public static function tokenInfo(string $token): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/api/v2/oauth2/info';
|
||||
$payload = [
|
||||
'access_token' => $token,
|
||||
];
|
||||
// {"ts":1234,"code":0,"data":{"mid":1234,"access_token":"1234","expires_in":7759292}}
|
||||
return Request::getJson(true, 'app', $url, Sign::common($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 新令牌信息
|
||||
* @param string $token
|
||||
* @return array
|
||||
*/
|
||||
public static function tokenInfoNew(string $token): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/x/passport-login/oauth2/info';
|
||||
$payload = [
|
||||
'access_key' => $token,
|
||||
];
|
||||
return Request::postJson(true, 'app', $url, Sign::common($payload));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 刷新令牌信息
|
||||
* @param string $token
|
||||
* @param string $r_token
|
||||
* @return array
|
||||
*/
|
||||
public static function tokenRefreshNew(string $token, string $r_token): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/x/passport-login/oauth2/refresh_token';
|
||||
$payload = [
|
||||
'access_key' => $token,
|
||||
'access_token' => $token,
|
||||
'refresh_token' => $r_token,
|
||||
];
|
||||
// {"message":"user not login","ts":1593111694,"code":-101}
|
||||
return Request::postJson(true, 'app', $url, Sign::common($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 刷新令牌信息
|
||||
* @param string $token
|
||||
* @param string $r_token
|
||||
* @return array
|
||||
*/
|
||||
public static function tokenRefresh(string $token, string $r_token): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/api/v2/oauth2/refresh_token';
|
||||
$payload = [
|
||||
'access_token' => $token,
|
||||
'refresh_token' => $r_token,
|
||||
];
|
||||
// {"message":"user not login","ts":1593111694,"code":-101}
|
||||
return Request::postJson(true, 'app', $url, Sign::common($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取公钥
|
||||
* @return array
|
||||
*/
|
||||
public static function getKey(): array
|
||||
{
|
||||
// $url = 'https://passport.bilibili.com/api/oauth2/getKey';
|
||||
$url = 'https://passport.bilibili.com/x/passport-login/web/key';
|
||||
$payload = [];
|
||||
return Request::getJson(true, 'app', $url, Sign::login($payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 刷新COOKIE
|
||||
* @param string $token
|
||||
* @return array
|
||||
*/
|
||||
public static function token2Cookie(string $token): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/api/login/sso';
|
||||
$payload = [
|
||||
'access_key' => $token,
|
||||
'gourl' => 'https%3A%2F%2Faccount.bilibili.com%2Faccount%2Fhome'
|
||||
];
|
||||
return Request::headers('app', $url, Sign::tv($payload));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
61
src/Api/PassportTv/ApiQrcode.php
Normal file
61
src/Api/PassportTv/ApiQrcode.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Api\PassportTv;
|
||||
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Sign\Sign;
|
||||
|
||||
class ApiQrcode
|
||||
{
|
||||
|
||||
/**
|
||||
* @use 获取authCode
|
||||
* @return array
|
||||
*/
|
||||
public static function authCode(): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code';
|
||||
$payload = [];
|
||||
$headers = [
|
||||
'content-type' => 'application/x-www-form-urlencoded',
|
||||
];
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"url":"https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/auth?auth_code=xxxx","auth_code":"xxxx"}}
|
||||
return Request::postJson(true, 'app', $url, Sign::tv($payload), $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 验证登录
|
||||
* @param string $auth_code
|
||||
* @return mixed
|
||||
*/
|
||||
public static function poll(string $auth_code): array
|
||||
{
|
||||
$url = 'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll';
|
||||
$payload = [
|
||||
'auth_code' => $auth_code,
|
||||
];
|
||||
$headers = [
|
||||
'content-type' => 'application/x-www-form-urlencoded',
|
||||
];
|
||||
// {"code":0,"message":"0","ttl":1,"data":{"mid":123,"access_token":"xxx","refresh_token":"xxx","expires_in":2592000}}
|
||||
return Request::postJson(true, 'app', $url, Sign::tv($payload), $headers);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
103
src/Bootstrap/Bootstrap.php
Normal file
103
src/Bootstrap/Bootstrap.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Bootstrap;
|
||||
|
||||
use Bhp\BiliInfo\BiliInfo;
|
||||
use Bhp\Cache\Cache;
|
||||
use Bhp\Console\Console;
|
||||
use Bhp\Core\Core;
|
||||
use Bhp\Device\Device;
|
||||
use Bhp\FilterWords\FilterWords;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Notice\Notice;
|
||||
use Bhp\Plugin\Plugin;
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Sign\Sign;
|
||||
use Bhp\Task\Task;
|
||||
use Bhp\TimeLock\TimeLock;
|
||||
use Bhp\User\User;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Bhp\Env\Env;
|
||||
use Bhp\Config\Config;
|
||||
|
||||
class Bootstrap extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $global_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $profile_name;
|
||||
|
||||
/**
|
||||
* @param string $global_path
|
||||
* @param array $argv
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $global_path, array $argv): void
|
||||
{
|
||||
$this->global_path = $global_path;
|
||||
$this->profile_name = Console::parse($argv);
|
||||
$this->superRegister();
|
||||
}
|
||||
|
||||
public function superRegister(): void
|
||||
{
|
||||
// 核心
|
||||
Core::getInstance($this->global_path, $this->profile_name);
|
||||
// 配置
|
||||
Config::getInstance();
|
||||
// 缓存中心
|
||||
Cache::getInstance();
|
||||
// 日志
|
||||
Log::getInstance();
|
||||
// 环境
|
||||
Env::getInstance();
|
||||
// 设备/取前缀
|
||||
Device::getInstance();
|
||||
// 请求中心
|
||||
Request::getInstance();
|
||||
// 时间锁
|
||||
TimeLock::getInstance();
|
||||
// 过滤词
|
||||
FilterWords::getInstance();
|
||||
// 签名
|
||||
Sign::getInstance();
|
||||
// 用户
|
||||
User::getInstance();
|
||||
// 通知中心
|
||||
Notice::getInstance();
|
||||
// 任务中心
|
||||
Task::getInstance();
|
||||
// 插件中心
|
||||
Plugin::getInstance();
|
||||
// 控制台
|
||||
Console::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Console::getInstance()->register();
|
||||
}
|
||||
}
|
||||
160
src/Cache/Cache.php
Normal file
160
src/Cache/Cache.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Cache;
|
||||
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Flintstone\Flintstone;
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
use Overtrue\Pinyin\Pinyin;
|
||||
|
||||
class Cache extends SingleTon
|
||||
{
|
||||
// 文档
|
||||
//matomo-org/component-cache
|
||||
// https://www.xeweb.net/flintstone/documentation/
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected array $caches = [];
|
||||
|
||||
/**
|
||||
* @var Flintstone
|
||||
*/
|
||||
protected Flintstone $cache;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $classname
|
||||
* @return void
|
||||
*/
|
||||
public static function initCache(?string $classname = null): void
|
||||
{
|
||||
$class_name = $classname ?? self::getInstance()->getCallClassName();
|
||||
//
|
||||
if (!array_key_exists($class_name, self::getInstance()->caches)) {
|
||||
// 判断字符串中是否有中文
|
||||
if (preg_match("/[\x7f-\xff]/", $class_name)) {
|
||||
$pinyin = new Pinyin(); // 默认
|
||||
$class_name = $pinyin->permalink($class_name); // yong-hu-ming
|
||||
}
|
||||
// 如果不存在缓存 初始化
|
||||
$database = self::getInstance()->removeSpecStr('cache_' . $class_name);
|
||||
$options = [
|
||||
'dir' => PROFILE_CACHE_PATH,
|
||||
'gzip' => true,
|
||||
'formatter' => new JsonFormatter()
|
||||
];
|
||||
self::getInstance()->caches[$class_name] = new Flintstone($database, $options);
|
||||
// ->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
|
||||
}
|
||||
print_r(array_keys(self::getInstance()->caches));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 写入值
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param string|null $classname
|
||||
* @return void
|
||||
*/
|
||||
public static function set(string $key, mixed $value, ?string $classname = null): void
|
||||
{
|
||||
// Set a key
|
||||
// $users->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
|
||||
self::getInstance()->getCache($classname)->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取值
|
||||
* @param string $key
|
||||
* @param string|null $classname
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function get(string $key, ?string $classname = null): mixed
|
||||
{
|
||||
// Get a key
|
||||
// $user = $users->get('bob');
|
||||
// echo 'Bob, your email is ' . $user['email'];
|
||||
return self::getInstance()->getCache($classname)->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 强转一下类型
|
||||
* @param string|null $classname
|
||||
* @return Flintstone
|
||||
*/
|
||||
protected function getCache(?string $classname = null): Flintstone
|
||||
{
|
||||
$class_name = $classname ?? $this->getCallClassName();
|
||||
if (!array_key_exists($class_name, $this->caches)) {
|
||||
failExit("当前类 $class_name 并未初始化缓存");
|
||||
}
|
||||
return $this->caches[$class_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取调用者类名
|
||||
* @return string
|
||||
*/
|
||||
protected function getCallClassName(): string
|
||||
{
|
||||
// basename(str_replace('\\', '/', __CLASS__));
|
||||
$backtraces = debug_backtrace();
|
||||
$temp = pathinfo(basename($backtraces[1]['file']))['filename'];
|
||||
//
|
||||
if ($temp == basename(str_replace('\\', '/', __CLASS__))) {
|
||||
return pathinfo(basename($backtraces[2]['file']))['filename'];
|
||||
} else {
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 去除特殊符号
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
protected function removeSpecStr(string $str): string
|
||||
{
|
||||
$specs = str_split("-.,:;'*?~`!@#$%^&+=)(<>{}]|\/、");
|
||||
foreach ($specs as $spec) {
|
||||
$str = str_replace($spec, '', $str);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取调用链类
|
||||
* @return mixed
|
||||
*/
|
||||
protected function backtraceClass(): mixed
|
||||
{
|
||||
// TODO 耦合度过高 需要解耦
|
||||
$backtraces = debug_backtrace();
|
||||
array_shift($backtraces);
|
||||
return pathinfo(basename($backtraces[2]['file']))['filename'];
|
||||
}
|
||||
}
|
||||
42
src/Config/Config.php
Normal file
42
src/Config/Config.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Config;
|
||||
|
||||
use Bhp\Util\Resource\BaseResource;
|
||||
|
||||
class Config extends BaseResource
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $filename = 'user.ini'): void
|
||||
{
|
||||
$this->loadResource($filename, 'ini');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写获取路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePath(string $filename): string
|
||||
{
|
||||
return str_replace("\\", "/", PROFILE_CONFIG_PATH . $filename);
|
||||
}
|
||||
}
|
||||
64
src/Console/Command/AppCommand.php
Normal file
64
src/Console/Command/AppCommand.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Console\Command;
|
||||
|
||||
use Ahc\Cli\Input\Command;
|
||||
use Ahc\Cli\IO\Interactor;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Plugin\Plugin;
|
||||
use Bhp\Task\Task;
|
||||
|
||||
class AppCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $desc = '[主要模式] 默认功能';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('mode:app', $this->desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Interactor $io
|
||||
* @return void
|
||||
*/
|
||||
public function interact(Interactor $io): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
Log::info("执行 $this->desc");
|
||||
//
|
||||
$plugins = Plugin::getPlugins();
|
||||
print_r($plugins);
|
||||
foreach ($plugins as $plugin) {
|
||||
Task::addTask($plugin['hook'], null);
|
||||
}
|
||||
//
|
||||
Task::execTasks();
|
||||
}
|
||||
}
|
||||
57
src/Console/Command/RestoreCommand.php
Normal file
57
src/Console/Command/RestoreCommand.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Console\Command;
|
||||
|
||||
use Ahc\Cli\Input\Command;
|
||||
use Ahc\Cli\IO\Interactor;
|
||||
use Bhp\Log\Log;
|
||||
|
||||
final class RestoreCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $desc = '[复位模式] 复位一些缓存以及设置';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('mode:restore', $this->desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Interactor $io
|
||||
* @return void
|
||||
*/
|
||||
public function interact(Interactor $io): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
Log::info("执行 $this->desc");
|
||||
|
||||
// 清理排程文件
|
||||
// 清理缓存文件
|
||||
}
|
||||
}
|
||||
54
src/Console/Command/ScriptCommand.php
Normal file
54
src/Console/Command/ScriptCommand.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Console\Command;
|
||||
|
||||
use Ahc\Cli\Input\Command;
|
||||
use Ahc\Cli\IO\Interactor;
|
||||
use Bhp\Log\Log;
|
||||
|
||||
final class ScriptCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $desc = '[脚本模式] 使用一些额外功能脚本';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('mode:script', $this->desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Interactor $io
|
||||
* @return void
|
||||
*/
|
||||
public function interact(Interactor $io): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
Log::info("执行 $this->desc");
|
||||
}
|
||||
}
|
||||
102
src/Console/Console.php
Normal file
102
src/Console/Console.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Console;
|
||||
|
||||
use Ahc\Cli\Application;
|
||||
use Bhp\Console\Command\AppCommand;
|
||||
use Bhp\Console\Command\RestoreCommand;
|
||||
use Bhp\Console\Command\ScriptCommand;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Exception;
|
||||
|
||||
class Console extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $logo = <<<LOGO
|
||||
________ ___ ___ ___ ___ ___ _______ ___ ________ _______ ________
|
||||
|\ __ \|\ \|\ \ |\ \|\ \|\ \|\ ___ \ |\ \ |\ __ \|\ ___ \ |\ __ \
|
||||
\ \ \|\ /\ \ \ \ \ \ \ \ \ \\\ \ \ __/|\ \ \ \ \ \|\ \ \ __/|\ \ \|\ \
|
||||
\ \ __ \ \ \ \ \ \ \ \ \ __ \ \ \_|/_\ \ \ \ \ ____\ \ \_|/_\ \ _ _\
|
||||
\ \ \|\ \ \ \ \ \____\ \ \ \ \ \ \ \ \_|\ \ \ \____\ \ \___|\ \ \_|\ \ \ \\ \|
|
||||
\ \_______\ \__\ \_______\ \__\ \__\ \__\ \_______\ \_______\ \__\ \ \_______\ \__\\ _\
|
||||
\|_______|\|__|\|_______|\|__|\|__|\|__|\|_______|\|_______|\|__| \|_______|\|__|\|__|
|
||||
|
||||
LOGO;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $argv;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected Application $app;
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 解析参数
|
||||
* @param array $argv
|
||||
* @param string $default
|
||||
* @return string
|
||||
*/
|
||||
public static function parse(array $argv, string $default = 'user'): string
|
||||
{
|
||||
try {
|
||||
// backup
|
||||
// $argv = $argv ?? $_SERVER['argv'];
|
||||
// $filename = str_contains($argv[1] ?? '', ':') ? $default : $args[1] ?? $default;
|
||||
|
||||
$argv = $argv ?? $_SERVER['argv'];
|
||||
self::getInstance()->argv = $argv;
|
||||
$app = new Application('parse');
|
||||
$args = $app->parse($argv);
|
||||
// 省略参数
|
||||
$filename = str_contains($args->args()[0] ?? '', ':') ? $default : $args->args()[0] ?? $default;
|
||||
unset($app);
|
||||
} catch (Exception $e) {
|
||||
failExit('解析命令行参数错误', ['msg' => $e->getMessage()]);
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app = new Application(getAppName(), getAppVersion());
|
||||
$this->app
|
||||
->add(new AppCommand(), 'm:a', true) // 模式1
|
||||
->add(new ScriptCommand(), 'm:s') // 模式2
|
||||
->add(new RestoreCommand(), 'm:r') // 模式3
|
||||
->logo($this->logo)
|
||||
->handle($this->argv);
|
||||
}
|
||||
|
||||
}
|
||||
64
src/Device/Device.php
Normal file
64
src/Device/Device.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Device;
|
||||
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Util\Resource\BaseResource;
|
||||
|
||||
class Device extends BaseResource
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $default_filename
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $filename = 'device.yaml'): void
|
||||
{
|
||||
$this->loadResource($filename, 'yaml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写真实路径获取
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePath(string $filename): string
|
||||
{
|
||||
return str_replace("\\", "/", PROFILE_DEVICE_PATH . $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写真实路径
|
||||
* @param string $filename
|
||||
* @param string $default_filename
|
||||
* @return string
|
||||
*/
|
||||
// protected function getRealFileName(string $filename, string $default_filename): string
|
||||
// {
|
||||
// $prefix = str_replace(strrchr($filename, "."), "", $filename) . '_';
|
||||
// $new_filename = $prefix . $default_filename;
|
||||
// // 自定义设备
|
||||
// if (is_file($this->getFilePath($new_filename))) {
|
||||
// Log::info('使用自定义设备参数' . $new_filename);
|
||||
// return $new_filename;
|
||||
// } else {
|
||||
// Log::info('使用默认设备参数' . $default_filename);
|
||||
// return $default_filename;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
136
src/Env/Env.php
Normal file
136
src/Env/Env.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Env;
|
||||
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Util\Resource\BaseResource;
|
||||
|
||||
class Env extends BaseResource
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $app_name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $app_version;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $app_branch;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $app_source;
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $filename = 'version.json'): void
|
||||
{
|
||||
set_time_limit(0);
|
||||
// header("Content-Type:text/html; charset=utf-8");
|
||||
// ini_set('date.timezone', 'Asia/Shanghai');
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
ini_set('display_errors', 'on');
|
||||
error_reporting(E_ALL);
|
||||
//
|
||||
$this->loadResource($filename, 'json');
|
||||
//
|
||||
$this->app_name = $this->resource->get('project', 'BiliHelper-personal');
|
||||
$this->app_version = $this->resource->get('version', '0.0.0.000000');
|
||||
$this->app_branch = $this->resource->get('branch', 'master');
|
||||
$this->app_source = $this->resource->get('source', 'https://github.com/lkeme/BiliHelper-personal');
|
||||
//
|
||||
$this->inspectConfigure()->inspectExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查是否开启
|
||||
* @return $this
|
||||
*/
|
||||
protected function inspectExtension(): Env
|
||||
{
|
||||
$default_extensions = ['curl', 'openssl', 'sockets', 'json', 'zlib', 'mbstring'];
|
||||
foreach ($default_extensions as $extension) {
|
||||
if (!extension_loaded($extension)) {
|
||||
Log::error("检查到项目依赖 $extension 扩展未加载。");
|
||||
Log::error("请在 php.ini中启用 $extension 扩展后重试。");
|
||||
Log::error("程序常见问题请移步 $this->app_source 文档部分查看。");
|
||||
failExit("");
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查php环境
|
||||
* @return $this
|
||||
*/
|
||||
protected function inspectConfigure(): Env
|
||||
{
|
||||
Log::info("欢迎使用 项目: $this->app_name@$this->app_branch 版本: $this->app_version");
|
||||
Log::info("使用说明请移步 $this->app_source 查看");
|
||||
|
||||
if (PHP_SAPI != 'cli') {
|
||||
failExit('Please run this script from command line .');
|
||||
}
|
||||
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
|
||||
failExit('Please upgrade PHP version < 8.0.0 .');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写获取路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePath(string $filename): string
|
||||
{
|
||||
return str_replace("\\", "/", APP_RESOURCES_PATH . $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Check: running in docker?
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDocker(): bool
|
||||
{
|
||||
// Win直接跳出
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
return false;
|
||||
}
|
||||
if (!file_exists('/.dockerenv')) {
|
||||
return false;
|
||||
}
|
||||
// 检查/proc/1/cgroup内是否包含"docker"等字符串;
|
||||
if (!is_file('/proc/self/cgroup') || !preg_match('%^\d+:\w+:/(docker|actions_job)/' . preg_quote(gethostname(), '%') . '\w+%sm', file_get_contents('/proc/self/cgroup'))) {
|
||||
return false;
|
||||
}
|
||||
// $processStack = explode(PHP_EOL, shell_exec('cat /proc/self/cgroup | grep docker'));
|
||||
// $processStack = array_filter($processStack);
|
||||
// return count($processStack) > 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
43
src/FilterWords/FilterWords.php
Normal file
43
src/FilterWords/FilterWords.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\FilterWords;
|
||||
|
||||
use Bhp\Util\Resource\BaseResource;
|
||||
|
||||
class FilterWords extends BaseResource
|
||||
{
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $filename = 'filter_library.json'): void
|
||||
{
|
||||
$this->loadResource($filename, 'json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 重写真实路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePath(string $filename): string
|
||||
{
|
||||
return str_replace("\\", "/", APP_RESOURCES_PATH . $filename);
|
||||
}
|
||||
}
|
||||
|
||||
181
src/Helpers.php
Normal file
181
src/Helpers.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
use Bhp\Cache\Cache;
|
||||
use Bhp\Config\Config;
|
||||
use Bhp\Device\Device;
|
||||
use Bhp\Env\Env;
|
||||
use Bhp\Log\Log;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @use 用户配置读取
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
function getConf(string $key, mixed $default = null, string $type = 'default'): mixed
|
||||
{
|
||||
return Config::getInstance()->get($key, $default, $type);
|
||||
}
|
||||
|
||||
/**用户
|
||||
* @use 配置写入
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
function setConf(string $key, mixed $value): void
|
||||
{
|
||||
Config::getInstance()->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 配置开关获取(大量调用独立抽取)
|
||||
* @param string $key
|
||||
* @param bool $default
|
||||
* @return bool
|
||||
*/
|
||||
function getEnable(string $key, bool $default = false): bool
|
||||
{
|
||||
return getConf($key . '.enable', $default, 'bool');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取用户相关信息(Login)
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
function getU(string $key): mixed
|
||||
{
|
||||
$value = '';
|
||||
$fillable = ['username', 'password', 'uid', 'csrf', 'cookie', 'access_token', 'refresh_token', 'sid'];
|
||||
if (in_array($key, $fillable)) {
|
||||
$value = Cache::get('auth_' . $key, 'Login');
|
||||
}
|
||||
return $value ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置用户相关信息(Login)
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
function setU(string $key, mixed $value): void
|
||||
{
|
||||
$fillable = ['username', 'password', 'uid', 'csrf', 'cookie', 'access_token', 'refresh_token', 'sid'];
|
||||
if (in_array($key, $fillable)) {
|
||||
Cache::set('auth_' . $key, $value, 'Login');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @use 获取APP名称
|
||||
* @return string
|
||||
*/
|
||||
function getAppName(): string
|
||||
{
|
||||
return Env::getInstance()->app_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取APP版本
|
||||
* @return string
|
||||
*/
|
||||
function getAppVersion(): string
|
||||
{
|
||||
return Env::getInstance()->app_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取APP主页
|
||||
* @return string
|
||||
*/
|
||||
function getAppHomePage(): string
|
||||
{
|
||||
return Env::getInstance()->app_source;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @use 错误退出
|
||||
* @param $message
|
||||
* @param array $context
|
||||
* @param int $delay
|
||||
* @return void
|
||||
*/
|
||||
#[NoReturn] function failExit($message, array $context = [], int $delay = 60 * 2): void
|
||||
{
|
||||
Log::error($message, $context);
|
||||
// 如果在docker环境中,延迟退出,方便查看错误
|
||||
if (Env::isDocker()) {
|
||||
// 暂停两分钟后自动退出
|
||||
sleep($delay);
|
||||
}
|
||||
die();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @use 获取设备信息
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
function getDevice(string $key, mixed $default = null, string $type = 'default'): mixed
|
||||
{
|
||||
return Device::getInstance()->get($key, $default, $type);
|
||||
}
|
||||
|
||||
///**
|
||||
// * @use 缓存读取
|
||||
// * @param string $key
|
||||
// * @param string $extra_name
|
||||
// * @return mixed
|
||||
// */
|
||||
//function getCache(string $key, string $extra_name = ''): mixed
|
||||
//{
|
||||
// return Cache::getInstance()->_get($key, $extra_name);
|
||||
//}
|
||||
//
|
||||
///**
|
||||
// * @use 缓存写入
|
||||
// * @param string $key
|
||||
// * @param $data
|
||||
// * @param string $extra_name
|
||||
// */
|
||||
//function setCache(string $key, $data, string $extra_name = ''): void
|
||||
//{
|
||||
// Cache::getInstance()->_set($key, $data, $extra_name);
|
||||
//}
|
||||
222
src/Log/Log.php
Normal file
222
src/Log/Log.php
Normal file
@ -0,0 +1,222 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Log;
|
||||
|
||||
use Bhp\Request\Request;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Bramus\Monolog\Formatter\ColoredLineFormatter;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
class Log extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var Logger|null
|
||||
*/
|
||||
protected ?Logger $_logger = null;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化日志服务
|
||||
* @return Logger
|
||||
*/
|
||||
protected function getLogger(): Logger
|
||||
{
|
||||
if (!$this->_logger instanceof Logger) {
|
||||
$logger = new Logger('BHP');
|
||||
// 日志等级 DEBUG ?? INFO
|
||||
$handler = new StreamHandler('php://stdout', getEnable('debug') ? Logger::DEBUG : Logger::INFO);
|
||||
$handler->setFormatter(new ColoredLineFormatter(null, null, 'Y-m-d H:i:s'));
|
||||
$logger->pushHandler($handler);
|
||||
$this->_logger = $logger;
|
||||
}
|
||||
return $this->_logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 通用
|
||||
* @param string $level
|
||||
* @param string $msg
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
protected function log(string $level, string $msg, array $context = []): void
|
||||
{
|
||||
// 拼装信息内容
|
||||
$message = $this->prefix() . $this->backtrace() . $msg;
|
||||
// 写入文件
|
||||
$this->writeLog($level, $message);
|
||||
|
||||
// DEBUG数据单独处理/不需要回调
|
||||
if ($level == 'DEBUG') {
|
||||
$this->getInstance()->getLogger()->debug($msg, $context);
|
||||
return;
|
||||
}
|
||||
// 匹配等级
|
||||
switch ($level) {
|
||||
case 'INFO':
|
||||
$level_id = Logger::INFO;
|
||||
$this->getInstance()->getLogger()->info($message, $context);
|
||||
break;
|
||||
case 'NOTICE':
|
||||
$level_id = Logger::NOTICE;
|
||||
$this->getInstance()->getLogger()->notice($message, $context);
|
||||
break;
|
||||
case 'WARNING':
|
||||
$level_id = Logger::WARNING;
|
||||
$this->getInstance()->getLogger()->warning($message, $context);
|
||||
break;
|
||||
case 'ERROR':
|
||||
$level_id = Logger::ERROR;
|
||||
$this->getInstance()->getLogger()->error($message, $context);
|
||||
break;
|
||||
default:
|
||||
$level_id = Logger::CRITICAL;
|
||||
$this->getInstance()->getLogger()->critical($message, $context);
|
||||
break;
|
||||
}
|
||||
// 回调
|
||||
$this->callback($level_id, $level, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 错误
|
||||
* @param mixed $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public static function error(mixed $message, array $context = []): void
|
||||
{
|
||||
self::getInstance()->log('ERROR', $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 警告
|
||||
* @param mixed $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public static function warning(mixed $message, array $context = []): void
|
||||
{
|
||||
self::getInstance()->log('WARNING', $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 提醒
|
||||
* @param mixed $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public static function notice(mixed $message, array $context = []): void
|
||||
{
|
||||
self::getInstance()->log('NOTICE', $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 信息
|
||||
* @param mixed $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public static function info(mixed $message, array $context = []): void
|
||||
{
|
||||
self::getInstance()->log('INFO', $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 调试
|
||||
* @param mixed $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public static function debug(mixed $message, array $context = []): void
|
||||
{
|
||||
self::getInstance()->log('DEBUG', $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 堆栈
|
||||
* @return string
|
||||
*/
|
||||
protected function backtrace(): string
|
||||
{
|
||||
$backtraces = debug_backtrace();
|
||||
return "(" . pathinfo(basename($backtraces[2]['file']))['filename'] . ") => ";
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 前缀
|
||||
* @return string
|
||||
*/
|
||||
protected function prefix(): string
|
||||
{
|
||||
if (getConf('print.multiple')) {
|
||||
// return '[' . (getConf('print.user_identity') ?? getConf('login_account.username')) . ']';
|
||||
return sprintf("[%s]", getConf('print.user_identity') ?? getConf('login_account.username'));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 写日志
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
*/
|
||||
protected function writeLog(string $type, string $message): void
|
||||
{
|
||||
if (getEnable('log')) {
|
||||
if ($type == 'DEBUG' && !getEnable('debug')) {
|
||||
return;
|
||||
}
|
||||
$filename = PROFILE_LOG_PATH . getConf('login_account.username') . ".log";
|
||||
$date = date('[Y-m-d H:i:s] ');
|
||||
$data = $date . ' Log.' . $type . ' ' . $message . PHP_EOL;
|
||||
file_put_contents($filename, $data, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 回调
|
||||
* @param int $levelId
|
||||
* @param string $level
|
||||
* @param mixed $message
|
||||
* @return void
|
||||
*/
|
||||
protected function callback(int $levelId, string $level, mixed $message): void
|
||||
{
|
||||
$callback_level = getConf('log.callback_level') ?? Logger::ERROR;
|
||||
if ($levelId >= $callback_level) {
|
||||
$url = str_replace('{account}', $this->prefix(), getConf('log.callback'));
|
||||
$url = str_replace('{level}', $level, $url);
|
||||
$url = str_replace('{message}', urlencode($message), $url);
|
||||
//
|
||||
Request::single('get', str_replace(' ', '%20', $url));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,75 +1,117 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Plugin;
|
||||
namespace Bhp\Notice;
|
||||
|
||||
use BiliHelper\Core\Log;
|
||||
use BiliHelper\Core\Curl;
|
||||
use BiliHelper\Util\FilterWords;
|
||||
use Bhp\FilterWords\FilterWords;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Request\Request;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
class Notice
|
||||
class Notice extends SingleTon
|
||||
{
|
||||
use FilterWords;
|
||||
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
private static array $json_headers = [
|
||||
protected array $headers = [
|
||||
'Content-Type' => 'application/json'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 推送消息
|
||||
* @param string $type
|
||||
* @param string $result
|
||||
* @param string $msg
|
||||
* @return void
|
||||
*/
|
||||
public static function push(string $type, string $result = '')
|
||||
public static function push(string $type, string $msg = ''): void
|
||||
{
|
||||
if (!getEnable('notify')) {
|
||||
return;
|
||||
// 开关
|
||||
if (!getEnable('notify')) return;
|
||||
// 过滤词
|
||||
if (self::getInstance()->filterMsgWords($msg)) return;
|
||||
//
|
||||
self::getInstance()->sendInfo($type, $msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 发送消息
|
||||
* @param string $type
|
||||
* @param string $msg
|
||||
* @return void
|
||||
*/
|
||||
protected function sendInfo(string $type, string $msg): void
|
||||
{
|
||||
$info = $this->fillContent($type, $msg);
|
||||
//
|
||||
if (getConf('notify_sct.sctkey')) {
|
||||
$this->sctSend($info);
|
||||
}
|
||||
if (self::filterResultWords($result)) {
|
||||
return;
|
||||
if (getConf('notify_sc.sckey')) {
|
||||
$this->scSend($info);
|
||||
}
|
||||
if (getConf('notify_telegram.bottoken') && getConf('notify_telegram.chatid')) {
|
||||
$this->teleSend($info);
|
||||
}
|
||||
if (getConf('notify_dingtalk.token')) {
|
||||
$this->dingTalkSend($info);
|
||||
}
|
||||
if (getConf('notify_pushplus.token')) {
|
||||
$this->pushPlusSend($info);
|
||||
}
|
||||
if (getConf('notify_gocqhttp.target_qq') && getConf('notify_gocqhttp.token') && getConf('notify_gocqhttp.url')) {
|
||||
$this->goCqhttp($info);
|
||||
}
|
||||
if (getConf('notify_debug.token') && getConf('notify_debug.url')) {
|
||||
$this->debug($info);
|
||||
}
|
||||
if (getConf('notify_we_com.token')) {
|
||||
$this->weCom($info);
|
||||
}
|
||||
if (getConf('notify_we_com_app.corp_id') && getConf('notify_we_com_app.corp_secret') && getConf('notify_we_com_app.agent_id')) {
|
||||
$this->weComApp($info);
|
||||
}
|
||||
if (getConf('notify_feishu.token')) {
|
||||
$this->feiShuSend($info);
|
||||
}
|
||||
$uname = getConf('uname', 'print') ?? getConf('username', 'login.account');
|
||||
self::sendInfoHandle($type, $uname, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 过滤信息
|
||||
* @param string $result
|
||||
* @param string $msg
|
||||
* @return bool
|
||||
*/
|
||||
private static function filterResultWords(string $result): bool
|
||||
protected function filterMsgWords(string $msg): bool
|
||||
{
|
||||
self::loadJsonData();
|
||||
$default_words = self::$store->get("Notice.default");
|
||||
$custom_words = explode(',', getConf('filter_words', 'notify'));
|
||||
$default_words = FilterWords::getInstance()->get("Notice.default");
|
||||
$custom_words = explode(',', getConf('notify.filter_words'));
|
||||
$total_words = array_merge($default_words, $custom_words);
|
||||
foreach ($total_words as $word) {
|
||||
if (empty($word)) continue;
|
||||
if (str_contains($result, $word)) {
|
||||
if (str_contains($msg, $word)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -77,51 +119,52 @@ class Notice
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 处理信息
|
||||
* @use 填充消息
|
||||
* @param string $type
|
||||
* @param string $uname
|
||||
* @param string $result
|
||||
* @return bool
|
||||
* @param string $msg
|
||||
* @return array
|
||||
*/
|
||||
private static function sendInfoHandle(string $type, string $uname, string $result): bool
|
||||
protected function fillContent(string $type, string $msg): array
|
||||
{
|
||||
$now_time = date('Y-m-d H:i:s');
|
||||
$uname = getConf('print.uname') ?? getConf('login_account.username');
|
||||
|
||||
$info = match ($type) {
|
||||
'update' => [
|
||||
'title' => '版本更新通知',
|
||||
'content' => "[$now_time] 用户: $uname 程序更新通知: $result"
|
||||
'content' => "[$now_time] 用户: $uname 程序更新通知: $msg"
|
||||
],
|
||||
'anchor' => [
|
||||
'title' => '天选时刻获奖记录',
|
||||
'content' => "[$now_time] 用户: $uname 在天选时刻中获得: $result"
|
||||
'content' => "[$now_time] 用户: $uname 在天选时刻中获得: $msg"
|
||||
],
|
||||
'raffle' => [
|
||||
'title' => '实物奖励获奖纪录',
|
||||
'content' => "[$now_time] 用户: $uname 在实物奖励中获得: $result"
|
||||
'content' => "[$now_time] 用户: $uname 在实物奖励中获得: $msg"
|
||||
],
|
||||
'gift' => [
|
||||
'title' => '活动礼物获奖纪录',
|
||||
'content' => "[$now_time] 用户: $uname 在活动礼物中获得: $result"
|
||||
'content' => "[$now_time] 用户: $uname 在活动礼物中获得: $msg"
|
||||
],
|
||||
'storm' => [
|
||||
'title' => '节奏风暴获奖纪录',
|
||||
'content' => "[$now_time] 用户: $uname 在节奏风暴中获得: $result"
|
||||
'content' => "[$now_time] 用户: $uname 在节奏风暴中获得: $msg"
|
||||
],
|
||||
'cookieRefresh' => [
|
||||
'title' => 'Cookie刷新',
|
||||
'content' => "[$now_time] 用户: $uname 刷新Cookie: $result"
|
||||
'content' => "[$now_time] 用户: $uname 刷新Cookie: $msg"
|
||||
],
|
||||
'todaySign' => [
|
||||
'title' => '每日签到',
|
||||
'content' => "[$now_time] 用户: $uname 签到: $result"
|
||||
'content' => "[$now_time] 用户: $uname 签到: $msg"
|
||||
],
|
||||
'banned' => [
|
||||
'title' => '任务小黑屋',
|
||||
'content' => "[$now_time] 用户: $uname 小黑屋: $result"
|
||||
'content' => "[$now_time] 用户: $uname 小黑屋: $msg"
|
||||
],
|
||||
'error' => [
|
||||
'title' => '程序运行错误',
|
||||
'content' => "[$now_time] 用户: $uname 错误详情: $result"
|
||||
'content' => "[$now_time] 用户: $uname 错误详情: $msg"
|
||||
],
|
||||
'key_expired' => [
|
||||
'title' => '监控KEY异常',
|
||||
@ -129,69 +172,29 @@ class Notice
|
||||
],
|
||||
'capsule_lottery' => [
|
||||
'title' => '直播扭蛋抽奖活动',
|
||||
'content' => "[$now_time] 用户: $uname 详情: $result"
|
||||
'content' => "[$now_time] 用户: $uname 详情: $msg"
|
||||
],
|
||||
'activity_lottery' => [
|
||||
'title' => '主站九宫格抽奖活动',
|
||||
'content' => "[$now_time] 用户: $uname 详情: $result"
|
||||
'content' => "[$now_time] 用户: $uname 详情: $msg"
|
||||
],
|
||||
'jury_leave_office' => [
|
||||
'title' => '已卸任風機委員',
|
||||
'content' => "[$now_time] 用户: $uname 详情: $result ,请及时关注風機委員连任状态哦~"
|
||||
'content' => "[$now_time] 用户: $uname 详情: $msg ,请及时关注風機委員连任状态哦~"
|
||||
],
|
||||
'jury_auto_apply' => [
|
||||
'title' => '嘗試連任風機委員',
|
||||
'content' => "[$now_time] 用户: $uname 详情: $result ,请及时关注風機委員连任状态哦~"
|
||||
'content' => "[$now_time] 用户: $uname 详情: $msg ,请及时关注風機委員连任状态哦~"
|
||||
],
|
||||
default => [
|
||||
'title' => '推送消息异常记录',
|
||||
'content' => "[$now_time] 用户: $uname 推送消息key错误: $type->$result"
|
||||
'content' => "[$now_time] 用户: $uname 推送消息key错误: $type->$msg"
|
||||
],
|
||||
};
|
||||
|
||||
// 添加前缀
|
||||
$info['title'] = "【BHP】" . $info['title'];
|
||||
|
||||
self::sendLog($info);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 推送消息
|
||||
* @param array $info
|
||||
*/
|
||||
private static function sendLog(array $info)
|
||||
{
|
||||
if (getConf('sctkey', 'notify.sct')) {
|
||||
self::sctSend($info);
|
||||
}
|
||||
if (getConf('sckey', 'notify.sc')) {
|
||||
self::scSend($info);
|
||||
}
|
||||
if (getConf('bottoken', 'notify.telegram') && getConf('chatid', 'notify.telegram')) {
|
||||
self::teleSend($info);
|
||||
}
|
||||
if (getConf('token', 'notify.dingtalk')) {
|
||||
self::dingTalkSend($info);
|
||||
}
|
||||
if (getConf('token', 'notify.pushplus')) {
|
||||
self::pushPlusSend($info);
|
||||
}
|
||||
if (getConf('target_qq', 'notify.gocqhttp') && getConf('token', 'notify.gocqhttp') && getConf('url', 'notify.gocqhttp')) {
|
||||
self::goCqhttp($info);
|
||||
}
|
||||
if (getConf('token', 'notify.debug') && getConf('url', 'notify.debug')) {
|
||||
self::debug($info);
|
||||
}
|
||||
if (getConf('token', 'notify.we_com')) {
|
||||
self::weCom($info);
|
||||
}
|
||||
if (getConf('corp_id', 'notify.we_com_app') && getConf('corp_secret', 'notify.we_com_app') && getConf('agent_id', 'notify.we_com_app')) {
|
||||
self::weComApp($info);
|
||||
}
|
||||
if (getConf('token', 'notify.feishu')) {
|
||||
self::feiShuSend($info);
|
||||
}
|
||||
//
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,10 +202,10 @@ class Notice
|
||||
* @doc https://developers.dingtalk.com/document/robots/custom-robot-access
|
||||
* @param array $info
|
||||
*/
|
||||
private static function dingTalkSend(array $info)
|
||||
protected function dingTalkSend(array $info): void
|
||||
{
|
||||
Log::info('使用DingTalk机器人推送消息');
|
||||
$url = 'https://oapi.dingtalk.com/robot/send?access_token=' . getConf('token', 'notify.dingtalk');
|
||||
$url = 'https://oapi.dingtalk.com/robot/send?access_token=' . getConf('notify_dingtalk.token');
|
||||
$payload = [
|
||||
'msgtype' => 'markdown',
|
||||
'markdown' => [
|
||||
@ -213,7 +216,7 @@ class Notice
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json;charset=utf-8'
|
||||
];
|
||||
$raw = Curl::put('other', $url, $payload, $headers);
|
||||
$raw = Request::put('other', $url, $payload, $headers);
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['errcode'] == 0) {
|
||||
Log::notice("推送消息成功: {$de_raw['errmsg']}");
|
||||
@ -227,17 +230,17 @@ class Notice
|
||||
* @doc https://core.telegram.org/bots/api#sendmessage
|
||||
* @param array $info
|
||||
*/
|
||||
private static function teleSend(array $info)
|
||||
protected function teleSend(array $info): void
|
||||
{
|
||||
Log::info('使用Tele机器人推送消息');
|
||||
$base_url = getConf('url', 'notify.telegram') ?: 'https://api.telegram.org/bot';
|
||||
$url = $base_url . getConf('bottoken', 'notify.telegram') . '/sendMessage';
|
||||
$base_url = getConf('notify_telegram.url') ?: 'https://api.telegram.org/bot';
|
||||
$url = $base_url . getConf('notify_telegram.bottoken') . '/sendMessage';
|
||||
$payload = [
|
||||
'chat_id' => getConf('chatid', 'notify.telegram'),
|
||||
'chat_id' => getConf('notify_telegram.chatid'),
|
||||
'text' => $info['content']
|
||||
];
|
||||
// {"ok":true,"result":{"message_id":7,"from":{"id":,"is_bot":true,"first_name":"","username":""},"chat":{"id":,"first_name":"","username":"","type":"private"},"date":,"text":""}}
|
||||
$raw = Curl::post('other', $url, $payload);
|
||||
$raw = Request::post('other', $url, $payload);
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['ok'] && array_key_exists('message_id', $de_raw['result'])) {
|
||||
Log::notice("推送消息成功: MSG_ID->{$de_raw['result']['message_id']}");
|
||||
@ -251,15 +254,15 @@ class Notice
|
||||
* @use https://sc.ftqq.com/
|
||||
* @param array $info
|
||||
*/
|
||||
private static function scSend(array $info)
|
||||
protected function scSend(array $info): void
|
||||
{
|
||||
Log::info('使用ServerChan推送消息');
|
||||
$url = 'https://sc.ftqq.com/' . getConf('sckey', 'notify.sc') . '.send';
|
||||
$url = 'https://sc.ftqq.com/' . getConf('notify_sc.sckey') . '.send';
|
||||
$payload = [
|
||||
'text' => $info['title'],
|
||||
'desp' => $info['content'],
|
||||
];
|
||||
$raw = Curl::post('other', $url, $payload);
|
||||
$raw = Request::post('other', $url, $payload);
|
||||
$de_raw = json_decode($raw, true);
|
||||
|
||||
if ($de_raw['errno'] == 0) {
|
||||
@ -274,15 +277,15 @@ class Notice
|
||||
* @doc https://sct.ftqq.com/
|
||||
* @param array $info
|
||||
*/
|
||||
private static function sctSend(array $info)
|
||||
protected function sctSend(array $info): void
|
||||
{
|
||||
Log::info('使用ServerChan(Turbo)推送消息');
|
||||
$url = 'https://sctapi.ftqq.com/' . getConf('sctkey', 'notify.sct') . '.send';
|
||||
$url = 'https://sctapi.ftqq.com/' . getConf('notify_sct.sctkey') . '.send';
|
||||
$payload = [
|
||||
'text' => $info['title'],
|
||||
'desp' => $info['content'],
|
||||
];
|
||||
$raw = Curl::post('other', $url, $payload);
|
||||
$raw = Request::post('other', $url, $payload);
|
||||
$de_raw = json_decode($raw, true);
|
||||
// {'message': '[AUTH]用户不存在或者权限不足', 'code': 40001, 'info': '用户不存在或者权限不足', 'args': [None]}
|
||||
// {'code': 0, 'message': '', 'data': {'pushid': 'xxxx', 'readkey': 'xxxxx', 'error': 'SUCCESS', 'errno': 0}}
|
||||
@ -298,16 +301,16 @@ class Notice
|
||||
* @doc http://www.pushplus.plus/doc/
|
||||
* @param array $info
|
||||
*/
|
||||
private static function pushPlusSend(array $info)
|
||||
protected function pushPlusSend(array $info): void
|
||||
{
|
||||
Log::info('使用PushPlus酱推送消息');
|
||||
$url = 'https://www.pushplus.plus/send';
|
||||
$payload = [
|
||||
'token' => getConf('token', 'notify.pushplus'),
|
||||
'token' => getConf('notify_pushplus.token'),
|
||||
'title' => $info['title'],
|
||||
'content' => $info['content']
|
||||
];
|
||||
$raw = Curl::put('other', $url, $payload, self::$json_headers);
|
||||
$raw = Request::put('other', $url, $payload, $this->headers);
|
||||
// {"code":200,"msg":"请求成功","data":"发送消息成功"}
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['code'] == 200) {
|
||||
@ -322,16 +325,16 @@ class Notice
|
||||
* @doc https://docs.go-cqhttp.org/api/
|
||||
* @param array $info
|
||||
*/
|
||||
private static function goCqhttp(array $info)
|
||||
protected function goCqhttp(array $info): void
|
||||
{
|
||||
Log::info('使用GoCqhttp推送消息');
|
||||
$url = getConf('url', 'notify.gocqhttp');
|
||||
$url = getConf('notify_gocqhttp.url');
|
||||
$payload = [
|
||||
'access_token' => getConf('token', 'notify.gocqhttp'),
|
||||
'user_id' => getConf('target_qq', 'notify.gocqhttp'),
|
||||
'access_token' => getConf('notify_gocqhttp.token'),
|
||||
'user_id' => getConf('notify_gocqhttp.target_qq'),
|
||||
'message' => $info['content']
|
||||
];
|
||||
$raw = Curl::get('other', $url, $payload);
|
||||
$raw = Request::get('other', $url, $payload);
|
||||
// {"data":{"message_id":123456},"retcode":0,"status":"ok"}
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['retcode'] == 0) {
|
||||
@ -346,20 +349,20 @@ class Notice
|
||||
* @doc https://localhost:8921/doc
|
||||
* @param array $info
|
||||
*/
|
||||
private static function debug(array $info)
|
||||
protected function debug(array $info): void
|
||||
{
|
||||
Log::info('使用Debug推送消息');
|
||||
$url = getConf('url', 'notify.debug');
|
||||
$url = getConf('notify_debug.url');
|
||||
$payload = [
|
||||
'receiver' => getConf('token', 'notify.debug'),
|
||||
'receiver' => getConf('notify_debug.token'),
|
||||
'title' => $info['title'],
|
||||
'body' => $info['content'],
|
||||
'url' => '',
|
||||
];
|
||||
$raw = Curl::post('other', $url, $payload);
|
||||
$raw = Request::post('other', $url, $payload);
|
||||
$de_raw = json_decode($raw, true);
|
||||
// {"success": true, "msg": null, "data": {"errcode": 0, "errmsg": "ok", "msgid": 1231, "token": "456"}}
|
||||
if ($de_raw['success'] == true) {
|
||||
if ($de_raw['success']) {
|
||||
Log::notice("推送消息成功: {$de_raw['data']['msgid']}");
|
||||
} else {
|
||||
Log::warning("推送消息失败: $raw");
|
||||
@ -371,10 +374,10 @@ class Notice
|
||||
* @doc https://open.work.weixin.qq.com/api/doc/90000/90136/91770
|
||||
* @param array $info
|
||||
*/
|
||||
private static function weCom(array $info)
|
||||
protected function weCom(array $info): void
|
||||
{
|
||||
Log::info('使用weCom推送消息');
|
||||
$url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=' . getConf('token', 'notify.we_com');
|
||||
$url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=' . getConf('notify_we_com.token');
|
||||
|
||||
$payload = [
|
||||
'msgtype' => 'markdown',
|
||||
@ -382,7 +385,7 @@ class Notice
|
||||
'content' => "{$info['title']} \n\n{$info['content']}"
|
||||
]
|
||||
];
|
||||
$raw = Curl::put('other', $url, $payload, self::$json_headers);
|
||||
$raw = Request::put('other', $url, $payload, $this->headers);
|
||||
// {"errcode":0,"errmsg":"ok","created_at":"1380000000"}
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['errcode'] == 0) {
|
||||
@ -397,13 +400,13 @@ class Notice
|
||||
* @doc https://open.work.weixin.qq.com/wwopen/devtool/interface?doc_id=10167
|
||||
* @param array $info
|
||||
*/
|
||||
private static function weComApp(array $info)
|
||||
protected function weComApp(array $info): void
|
||||
{
|
||||
Log::info('使用weComApp推送消息');
|
||||
$corp_id = getConf('corp_id', 'notify.we_com_app');
|
||||
$corp_secret = getConf('corp_secret', 'notify.we_com_app');
|
||||
$agent_id = getConf('agent_id', 'notify.we_com_app');
|
||||
$to_user = getConf('to_user', 'notify.we_com_app') ?? '@all';
|
||||
$corp_id = getConf('notify_we_com_app.corp_id');
|
||||
$corp_secret = getConf('notify_we_com_app.corp_secret' );
|
||||
$agent_id = getConf('notify_we_com_app.agent_id');
|
||||
$to_user = getConf('notify_we_com_app.to_user') ?? '@all';
|
||||
|
||||
// 获取token
|
||||
$url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken';
|
||||
@ -411,7 +414,7 @@ class Notice
|
||||
'corpid' => $corp_id,
|
||||
'corpsecret' => $corp_secret,
|
||||
];
|
||||
$raw = Curl::get('other', $url, $payload);
|
||||
$raw = Request::get('other', $url, $payload);
|
||||
// {"errcode":0,"errmsg":"ok","created_at":"1380000000"}
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['errcode'] == 0) {
|
||||
@ -430,7 +433,7 @@ class Notice
|
||||
'content' => "{$info['title']} \n\n{$info['content']}"
|
||||
]
|
||||
];
|
||||
$raw = Curl::put('other', $url, $payload, self::$json_headers);
|
||||
$raw = Request::put('other', $url, $payload, $this->headers);
|
||||
// {"errcode":0,"errmsg":"ok","created_at":"1380000000"}
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['errcode'] == 0) {
|
||||
@ -446,10 +449,10 @@ class Notice
|
||||
* @doc https://developers.dingtalk.com/document/robots/custom-robot-access
|
||||
* @param array $info
|
||||
*/
|
||||
private static function feiShuSend(array $info)
|
||||
protected function feiShuSend(array $info): void
|
||||
{
|
||||
Log::info('使用飞书webhook机器人推送消息');
|
||||
$url = 'https://open.feishu.cn/open-apis/bot/v2/hook/' . getConf('token', 'notify.feishu');
|
||||
$url = 'https://open.feishu.cn/open-apis/bot/v2/hook/' . getConf('notify_feishu.token');
|
||||
$payload = [
|
||||
'msg_type' => 'text',
|
||||
'content' => [
|
||||
@ -459,7 +462,7 @@ class Notice
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json;charset=utf-8'
|
||||
];
|
||||
$raw = Curl::put('other', $url, $payload, $headers);
|
||||
$raw = Request::put('other', $url, $payload, $headers);
|
||||
$de_raw = json_decode($raw, true);
|
||||
if ($de_raw['StatusCode'] == 0) {
|
||||
Log::notice("推送消息成功: {$de_raw['StatusCode']}");
|
||||
@ -468,4 +471,7 @@ class Notice
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,33 +1,25 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BiliHelper\Exceptions;
|
||||
namespace Bhp\Plugin;
|
||||
|
||||
use Exception;
|
||||
|
||||
class TaskException extends Exception
|
||||
abstract class BasePlugin
|
||||
{
|
||||
|
||||
use BasePluginInfo;
|
||||
}
|
||||
|
||||
|
||||
141
src/Plugin/BasePluginInfo.php
Normal file
141
src/Plugin/BasePluginInfo.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Plugin;
|
||||
|
||||
trait BasePluginInfo
|
||||
{
|
||||
/**
|
||||
* 插件信息
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected array $info_template = [
|
||||
'hook' => __CLASS__, // Hook名称
|
||||
'name' => 'name', // 插件名称
|
||||
'version' => 'version', // 插件版本
|
||||
'desc' => 'desc', // 插件描述
|
||||
'author' => 'Lkeme',// 作者
|
||||
'priority' => 0, // 插件优先级
|
||||
'cycle' => 'cycle', // 运行周期
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected ?array $info;
|
||||
|
||||
/**
|
||||
* @use 设置Hook
|
||||
* @param string $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setHook(string $value, string $key = 'hook'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置名称
|
||||
* @param string $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setName(string $value, string $key = 'name'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置版本
|
||||
* @param string $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setVersion(string $value, string $key = 'version'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置描述
|
||||
* @param string $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setDesc(string $value, string $key = 'desc'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置优先级
|
||||
* @param int $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setPriority(int $value, string $key = 'priority'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置运行周期
|
||||
* @param string $value
|
||||
* @param string $key
|
||||
* @return $this
|
||||
*/
|
||||
protected function setCycle(string $value, string $key = 'name'): static
|
||||
{
|
||||
$this->info[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 返回插件信息
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getPluginInfo(): array
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @return string
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
return $name . $value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,33 +1,27 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BiliHelper\Exceptions;
|
||||
namespace Bhp\Plugin;
|
||||
|
||||
use Exception;
|
||||
use Bhp\Util\Resource\BaseResourcePoly;
|
||||
|
||||
class SingletonException extends Exception
|
||||
abstract class BasePluginRW extends BaseResourcePoly
|
||||
{
|
||||
|
||||
use BasePluginInfo;
|
||||
}
|
||||
|
||||
|
||||
224
src/Plugin/Plugin.php
Normal file
224
src/Plugin/Plugin.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Plugin;
|
||||
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
class Plugin extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @use 监听插件的启用/关闭|UUID下标
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
protected array $_staff = [];
|
||||
|
||||
/**
|
||||
* @use 保存所有插件信息
|
||||
* @var array
|
||||
*/
|
||||
protected array $_plugins = [];
|
||||
|
||||
/**
|
||||
* @use 保存插件优先级信息
|
||||
* @var array
|
||||
*/
|
||||
protected array $_priority = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
$this->detector();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getPlugins(): array
|
||||
{
|
||||
return self::getInstance()->_plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getPluginsPriority(): array
|
||||
{
|
||||
return self::getInstance()->_priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getPluginsStaff(): array
|
||||
{
|
||||
return self::getInstance()->_staff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 这个是全局使用的触发钩子动作方法
|
||||
* @param string $hook
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
public function trigger(string $hook, mixed...$params): string
|
||||
{
|
||||
// 首先需要判断一下$hook 存不存在
|
||||
if (isset($this->_staff[$hook]) && is_array($this->_staff[$hook]) && count($this->_staff[$hook]) > 0) {
|
||||
$plugin_func_result = '';
|
||||
// 如果存在定义 $plugin_func_result
|
||||
foreach ($this->_staff[$hook] as $staff) {
|
||||
// 如果只是记录 请不要返回
|
||||
$plugin_func_result = '';
|
||||
$class = &$staff[0]; // 引用过来的类
|
||||
$method = $staff[1]; // 类下面的方法
|
||||
if (method_exists($class, $method)) {
|
||||
$func_result = $class->$method(...$params);
|
||||
if (is_numeric($func_result)) {
|
||||
// 这里判断返回值是不是字符串,如果不是将不进行返回到页面上
|
||||
$plugin_func_result .= $func_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $plugin_func_result ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 这里是在插件中使用的方法 用来注册插件
|
||||
* @param object $class_obj
|
||||
* @param string $method
|
||||
* @return void
|
||||
*/
|
||||
public function register(object &$class_obj, string $method): void
|
||||
{
|
||||
$hook = get_class($class_obj);
|
||||
// 获取类名和方法名链接起来做下标
|
||||
$func_class = $hook . '->' . $method;
|
||||
// 将类和方法放入监听数组中 以$func_class做下标
|
||||
$this->_staff[$hook][$func_class] = array(&$class_obj, $method);
|
||||
// 每个插件必须实现的 getPluginInfo 获取插件信息
|
||||
$this->addPluginInfo($hook, $class_obj->getPluginInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hook
|
||||
* @param array $info
|
||||
* @return void
|
||||
*/
|
||||
protected function addPluginInfo(string $hook, array $info): void
|
||||
{
|
||||
$this->validatePlugins($hook, $info);
|
||||
//
|
||||
$this->_plugins[$hook] = $info;
|
||||
$this->_priority[] = $info['priority'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hook
|
||||
* @param array $info
|
||||
* @return void
|
||||
*/
|
||||
protected function validatePlugins(string $hook, array $info): void
|
||||
{
|
||||
// 插件信息缺失
|
||||
$fillable = ['hook', 'name', 'version', 'desc', 'priority', 'cycle'];
|
||||
foreach ($fillable as $val) {
|
||||
if (!array_key_exists($val, $info)) {
|
||||
failExit("加载 $hook 插件错误,插件信息缺失,请检查修正.");
|
||||
}
|
||||
}
|
||||
// 插件名冲突
|
||||
if (array_key_exists($hook, $this->_plugins)) {
|
||||
failExit("加载 $hook 插件错误,插件名冲突,请检查修正.");
|
||||
}
|
||||
// 插件优先级冲突
|
||||
if (in_array($info['priority'], $this->_priority)) {
|
||||
failExit("加载 $hook 插件错误,插件优先级冲突,请检查修正.");
|
||||
}
|
||||
// 插件优先级定义
|
||||
if ($info['priority'] < 1000) {
|
||||
failExit("加载 $hook 插件错误,插件优先级定义错误,请检查修正.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化插件(all)
|
||||
* @return void
|
||||
*/
|
||||
protected function detector(): void
|
||||
{
|
||||
// 主要功能为将插件需要执行功能放入 $_staff
|
||||
$plugins = $this->getActivePlugins();
|
||||
foreach ($plugins as $plugin) {
|
||||
// 这里将所有插件践行初始化
|
||||
// 路径请自己注意
|
||||
if (@file_exists($plugin['path'])) {
|
||||
include_once($plugin['path']);
|
||||
// 此时设定 文件夹名称 文件名称 类名 是统一的 如果想设定不统一请自己在get_active_plugins()内进行实现
|
||||
$class = $plugin['name'];
|
||||
if (class_exists($class)) {
|
||||
// 初始化所有插件类
|
||||
new $class($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->sortPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取插件信息(all)
|
||||
* @use 假定了插件在根目录的/plugin
|
||||
* @use 假定插件的入口和插件文件夹的名字是一样的
|
||||
* @use 注意:这个执行文件我放在了根目录 以下路径请根据实际情况获取
|
||||
* @return array
|
||||
*/
|
||||
protected function getActivePlugins(): array
|
||||
{
|
||||
$plugins = [];
|
||||
$plugin_dir_name_arr = scandir(APP_PLUGIN_PATH);
|
||||
//
|
||||
foreach ($plugin_dir_name_arr as $_ => $v) {
|
||||
if ($v == "." || $v == "..") {
|
||||
continue;
|
||||
}
|
||||
// /plugin/Test/Test.php
|
||||
if (is_dir(APP_PLUGIN_PATH . $v)) {
|
||||
$path = APP_PLUGIN_PATH . $v . DIRECTORY_SEPARATOR . $v . '.php';
|
||||
$plugins[] = ['name' => $v, 'path' => $path];
|
||||
}
|
||||
}
|
||||
//
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 插件排序
|
||||
* @param string $column_key
|
||||
* @param int $sort_order
|
||||
* @return void
|
||||
*/
|
||||
protected function sortPlugins(string $column_key = 'priority', int $sort_order = SORT_ASC): void
|
||||
{
|
||||
$arr = array_column($this->_plugins, $column_key);
|
||||
array_multisort($arr, $sort_order, $this->_plugins);
|
||||
}
|
||||
|
||||
}
|
||||
164
src/Request/MultiRequest.php
Normal file
164
src/Request/MultiRequest.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Request;
|
||||
|
||||
use Closure;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Pool;
|
||||
use GuzzleHttp\Psr7\Request as PRequest;
|
||||
|
||||
class MultiRequest
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected Client $client;
|
||||
|
||||
protected array $headers = [];
|
||||
protected array $options = [];
|
||||
protected Closure $successCallback;
|
||||
protected Closure $errorCallback;
|
||||
protected array$urls = [];
|
||||
protected string$method;
|
||||
protected int $concurrency = 10;
|
||||
|
||||
/**
|
||||
* @param Client $client
|
||||
*/
|
||||
public function __construct(Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Client $client
|
||||
* @return MultiRequest
|
||||
*/
|
||||
public static function newMultiRequest(Client $client): MultiRequest
|
||||
{
|
||||
return new self($client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $headers
|
||||
* @return $this
|
||||
*/
|
||||
public function withHeaders(array $headers): static
|
||||
{
|
||||
$this->headers = array_merge($this->headers, $headers);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $options
|
||||
* @return $this
|
||||
*/
|
||||
public function withOptions($options): static
|
||||
{
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $concurrency
|
||||
* @return $this
|
||||
*/
|
||||
public function concurrency($concurrency): static
|
||||
{
|
||||
$this->concurrency = $concurrency;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure $success
|
||||
* @return $this
|
||||
*/
|
||||
public function success(Closure $success): static
|
||||
{
|
||||
$this->successCallback = $success;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure $error
|
||||
* @return $this
|
||||
*/
|
||||
public function error(Closure $error): static
|
||||
{
|
||||
$this->errorCallback = $error;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $urls
|
||||
* @return $this
|
||||
*/
|
||||
public function urls(array $urls): static
|
||||
{
|
||||
$this->urls = $urls;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function get(): void
|
||||
{
|
||||
$this->method = 'GET';
|
||||
$this->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function post(): void
|
||||
{
|
||||
$this->method = 'POST';
|
||||
$this->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function send(): void
|
||||
{
|
||||
$client = $this->client;
|
||||
|
||||
$requests = function ($urls) use ($client) {
|
||||
foreach ($urls as $url) {
|
||||
if (is_string($url)) {
|
||||
yield new PRequest($this->method, $url, $this->headers);
|
||||
} else {
|
||||
yield $url;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$pool = new Pool($client, $requests($this->urls), [
|
||||
'concurrency' => $this->concurrency,
|
||||
'fulfilled' => $this->successCallback,
|
||||
'rejected' => $this->errorCallback,
|
||||
'options' => $this->options
|
||||
]);
|
||||
|
||||
$promise = $pool->promise();
|
||||
$promise->wait();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
565
src/Request/Request.php
Normal file
565
src/Request/Request.php
Normal file
@ -0,0 +1,565 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Request;
|
||||
|
||||
use Bhp\Cache\Cache;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Util\ArrayR\ArrayR;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Bhp\Util\Exceptions\MethodNotFoundException;
|
||||
use Bhp\Util\Exceptions\ResponseEmptyException;
|
||||
use Bhp\Util\Fake\Fake;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @method static get(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static getResponse(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static getJson(?bool $associative, string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static post(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static postResponse(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static postJson(?bool $associative, string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static put(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static putResponse(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
* @method static putJson(?bool $associative, string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0)
|
||||
*/
|
||||
class Request extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $caches;
|
||||
|
||||
/**
|
||||
* @var Client|null
|
||||
*/
|
||||
protected ?Client $client = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $retry_times;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected float $timeout;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected ?string $buvid = null;
|
||||
|
||||
/**
|
||||
* @param int $min_rt
|
||||
* @param int $max_rt
|
||||
* @param float $timeout
|
||||
* @return void
|
||||
*/
|
||||
public function init(int $min_rt = 0, int $max_rt = 40, float $timeout = 30.0): void
|
||||
{
|
||||
Cache::initCache();
|
||||
$this->retry_times = range($min_rt, $max_rt);
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化客户端
|
||||
* @param string $request_id
|
||||
* @param array $config
|
||||
* @return Request
|
||||
*/
|
||||
protected function withClient(string $request_id, array $config = []): static
|
||||
{
|
||||
if (is_null($this->client)) {
|
||||
$this->client = new Client($config);
|
||||
}
|
||||
// clone 对象深拷贝
|
||||
$this->setRequest($request_id, 'client', clone $this->client);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 请求地址
|
||||
* @param string $request_id
|
||||
* @param string $url
|
||||
* @return $this
|
||||
*/
|
||||
protected function withUrl(string $request_id, string $url): static
|
||||
{
|
||||
$this->setRequest($request_id, 'url', $url);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 请求方式
|
||||
* @param string $request_id
|
||||
* @param string $method
|
||||
* @return $this
|
||||
*/
|
||||
protected function withMethod(string $request_id, string $method): static
|
||||
{
|
||||
$this->setRequest($request_id, 'method', $method);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 请求头
|
||||
* @param string $request_id
|
||||
* @param string $os
|
||||
* @param array $headers
|
||||
* @return $this
|
||||
*/
|
||||
protected function withHeaders(string $request_id, string $os = 'app', array $headers = []): static
|
||||
{
|
||||
// 从缓存中加载 如果存在就赋值 否则默认值
|
||||
if (is_null($this->buvid)) {
|
||||
$this->buvid = ($tmp = Cache::get('buvid')) ? $tmp : Fake::buvid();
|
||||
Cache::set('buvid', $this->buvid);
|
||||
}
|
||||
//
|
||||
$app_headers = [
|
||||
'env' => 'prod',
|
||||
'APP-KEY' => 'android',
|
||||
'Buvid' => $this->buvid,
|
||||
'Accept' => '*/*',
|
||||
'Accept-Encoding' => 'gzip',
|
||||
'Accept-Language' => 'zh-cn',
|
||||
'Connection' => 'keep-alive',
|
||||
'User-Agent' => getDevice('platform.headers.app_ua'),
|
||||
// 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
// 'User-Agent' => 'Mozilla/5.0 BiliDroid/5.51.1 (bbcallen@gmail.com)',
|
||||
// 'Referer' => 'https://live.bilibili.com/',
|
||||
];
|
||||
//
|
||||
$pc_headers = [
|
||||
'Accept' => "application/json, text/plain, */*",
|
||||
'Accept-Encoding' => 'gzip, deflate',
|
||||
'Accept-Language' => "zh-CN,zh;q=0.9",
|
||||
'User-Agent' => getDevice('platform.headers.pc_ua'),
|
||||
// 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
// 'Referer' => 'https://live.bilibili.com/',
|
||||
];
|
||||
//
|
||||
$other_headers = [
|
||||
'User-Agent' => getDevice('platform.headers.other_ua'),
|
||||
];
|
||||
$default_headers = ${$os . "_headers"} ?? $other_headers;
|
||||
if (in_array($os, ['app', 'pc']) && getU('cookie') != "") {
|
||||
$default_headers['Cookie'] = getU('cookie');
|
||||
}
|
||||
//
|
||||
$this->setRequest($request_id, 'headers', array_merge($default_headers, $headers));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 客户端配置
|
||||
* @param string $request_id
|
||||
* @param array $add_options
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return Request
|
||||
*/
|
||||
protected function withOptions(string $request_id, array $add_options, array $headers = [], float $timeout = 30.0): static
|
||||
{
|
||||
$default_options = [
|
||||
// 'connect_timeout' => 10,
|
||||
// 'debug' => false,
|
||||
'headers' => $headers,
|
||||
'timeout' => $timeout,
|
||||
'http_errors' => false,
|
||||
'verify' => getConf('network_ssl.verify', false, 'bool'),
|
||||
];
|
||||
if (getEnable('network_proxy')) {
|
||||
$default_options['proxy'] = getConf('network_proxy.proxy');
|
||||
}
|
||||
//
|
||||
$this->setRequest($request_id, 'options', array_merge($default_options, $add_options));
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 处理请求
|
||||
* @param string $request_id
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected function handle(string $request_id): ResponseInterface
|
||||
{
|
||||
$client = (object)$this->getRequest($request_id, 'client');
|
||||
$url = (string)$this->getRequest($request_id, 'url');
|
||||
$method = (string)$this->getRequest($request_id, 'method');
|
||||
$options = (array)$this->getRequest($request_id, 'options');
|
||||
//
|
||||
foreach ($this->retry_times as $retry) {
|
||||
try {
|
||||
// $response = $this->client->get($url, $options);
|
||||
// $response = $this->client->$method($url, $options);
|
||||
// 稍有性能损耗,不过影响不大
|
||||
$response = call_user_func_array([$client, $method], [$url, $options]);
|
||||
if (is_null($response) or empty($response)) throw new ResponseEmptyException("Value IsEmpty");
|
||||
return $response;
|
||||
} catch (RequestException $e) {
|
||||
// var_dump($e->getRequest());
|
||||
if ($e->hasResponse()) var_dump($e->getResponse());
|
||||
} catch (ResponseEmptyException|Exception $e) {
|
||||
// $e->getHandlerContext()
|
||||
// var_dump($e);
|
||||
}
|
||||
Log::warning("Target -> URL: $url METHOD: $method");
|
||||
Log::warning("CURl -> RETRY: $retry ERROR: {$e->getMessage()} ERRNO: {$e->getCode()} STATUS: Waiting for recovery!");
|
||||
sleep(15);
|
||||
}
|
||||
failExit('网络异常,超出最大尝试次数,退出程序~');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method GetResponse
|
||||
* @param string $os
|
||||
* @param string $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected static function _getResponse(string $os, string $url, array $params = [], array $headers = [], float $timeout = 30.0): ResponseInterface
|
||||
{
|
||||
//
|
||||
$rid = self::getInstance()->startRequest();
|
||||
//
|
||||
Log::debug("[GET#$rid] $url ", $params);
|
||||
//
|
||||
$payload['query'] = count($params) ? $params : [];
|
||||
//
|
||||
$response = self::getInstance()
|
||||
->withClient($rid)
|
||||
->withUrl($rid, $url)
|
||||
->withMethod($rid, 'get')
|
||||
->withHeaders($rid, $os, $headers)
|
||||
->withOptions($rid, $payload, $headers, $timeout)
|
||||
->handle($rid);
|
||||
//
|
||||
self::getInstance()->stopRequest($rid);
|
||||
//
|
||||
Log::debug("[GET#$rid] " . $response->getBody());
|
||||
//
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method Get
|
||||
* @param mixed ...$params
|
||||
* @return string
|
||||
*/
|
||||
protected static function _get(mixed ...$params): string
|
||||
{
|
||||
$response = self::getResponse(...$params);
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method GetJson
|
||||
* @param bool|null $associative
|
||||
* @param mixed ...$params
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function _getJson(?bool $associative = null, mixed...$params): mixed
|
||||
{
|
||||
$response = self::get(...$params);
|
||||
// JSON_UNESCAPED_UNICODE 当该参数为 TRUE 时,将返回 array 而非 object 。
|
||||
return json_decode($response, $associative);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method PostResponse
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected static function _postResponse($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): ResponseInterface
|
||||
{
|
||||
//
|
||||
$rid = self::getInstance()->startRequest();
|
||||
//
|
||||
Log::debug("[POST#$rid] $url ", $params);
|
||||
//
|
||||
$payload['form_params'] = count($params) ? $params : [];
|
||||
//
|
||||
$response = self::getInstance()
|
||||
->withClient($rid)
|
||||
->withUrl($rid, $url)
|
||||
->withMethod($rid, 'post')
|
||||
->withHeaders($rid, $os, $headers)
|
||||
->withOptions($rid, $payload, $headers, $timeout)
|
||||
->handle($rid);
|
||||
//
|
||||
self::getInstance()->stopRequest($rid);
|
||||
//
|
||||
Log::debug("[POST#$rid] " . $response->getBody());
|
||||
//
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method Post
|
||||
* @param mixed ...$params
|
||||
* @return string
|
||||
*/
|
||||
protected static function _post(mixed ...$params): string
|
||||
{
|
||||
$response = self::postResponse(...$params);
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method PostJson
|
||||
* @param bool|null $associative
|
||||
* @param mixed ...$params
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function _postJson(?bool $associative = null, mixed...$params): mixed
|
||||
{
|
||||
$response = self::post(...$params);
|
||||
// JSON_UNESCAPED_UNICODE
|
||||
return json_decode($response, $associative);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method PutResponse
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected static function _putResponse($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): ResponseInterface
|
||||
{
|
||||
//
|
||||
$rid = self::getInstance()->startRequest();
|
||||
//
|
||||
Log::debug("[PUT#$rid] $url ", $params);
|
||||
//
|
||||
$payload['json'] = count($params) ? $params : [];
|
||||
//
|
||||
$response = self::getInstance()
|
||||
->withClient($rid)
|
||||
->withUrl($rid, $url)
|
||||
->withMethod($rid, 'post')
|
||||
->withHeaders($rid, $os, $headers)
|
||||
->withOptions($rid, $payload, $headers, $timeout)
|
||||
->handle($rid);
|
||||
//
|
||||
self::getInstance()->stopRequest($rid);
|
||||
//
|
||||
Log::debug("[PUT#$rid] " . $response->getBody());
|
||||
//
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method Put
|
||||
* @param mixed ...$params
|
||||
* @return string
|
||||
*/
|
||||
protected static function _put(mixed ...$params): string
|
||||
{
|
||||
$response = self::putResponse(...$params);
|
||||
return (string)$response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Method PutJson
|
||||
* @param bool|null $associative
|
||||
* @param mixed ...$params
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function __putJson(?bool $associative = null, mixed...$params): mixed
|
||||
{
|
||||
$response = self::put(...$params);
|
||||
// JSON_UNESCAPED_UNICODE
|
||||
return json_decode($response, $associative);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 下载文件
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param string $filepath
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function download($os, $url, string $filepath, array $params = [], array $headers = [], float $timeout = 600.0): string
|
||||
{
|
||||
$params = array_merge($params, [
|
||||
'sink' => $filepath,
|
||||
]);
|
||||
return self::get($os, $url, $params, $headers, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 单次请求
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param array $payload
|
||||
* @param array $headers
|
||||
* @param int $timeout
|
||||
* @return bool|string|null
|
||||
*/
|
||||
public static function single(string $method, string $url, array $payload = [], array $headers = [], int $timeout = 10): bool|string|null
|
||||
{
|
||||
Log::debug("[SINGLE] $url ", $payload);
|
||||
//
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'method' => strtoupper($method),
|
||||
'header' => ArrayR::toStr($headers),
|
||||
'content' => http_build_query($payload),
|
||||
'timeout' => $timeout,
|
||||
),
|
||||
);
|
||||
$result = $url ? @file_get_contents($url, false, stream_context_create($options)) : null;
|
||||
//
|
||||
Log::debug("[SINGLE] $result");
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
// postAsync getAsync
|
||||
protected static function multiple(string $os, array $tasks = [], float $timeout = 30.0)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function standardizeParam($param): array
|
||||
{
|
||||
return array_map(function ($item) {
|
||||
if (is_array($item)) {
|
||||
return $this->standardizeParam($item);
|
||||
} else {
|
||||
return (string)$item;
|
||||
}
|
||||
}, $param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
* @throws MethodNotFoundException
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments): mixed
|
||||
{
|
||||
$protectedName = '_' . $name;
|
||||
if (method_exists(self::class, $protectedName)) {
|
||||
return self::$protectedName(...$arguments);
|
||||
}
|
||||
throw new MethodNotFoundException('Call undefined method ' . self::class . ':' . $name . '()');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 开始请求
|
||||
* @return string
|
||||
*/
|
||||
protected function startRequest(): string
|
||||
{
|
||||
$request_id = Fake::hash();
|
||||
$this->caches[$request_id] = [];
|
||||
return $request_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_id
|
||||
* @param string $key
|
||||
* @param mixed $values
|
||||
* @return void
|
||||
*/
|
||||
protected function setRequest(string $request_id, string $key, mixed $values): void
|
||||
{
|
||||
$this->caches[$request_id][$key] = $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $request_id
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getRequest(string $request_id, string $key): mixed
|
||||
{
|
||||
return $this->caches[$request_id][$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 结束请求
|
||||
* @param string $request_id
|
||||
* @return void
|
||||
*/
|
||||
protected function stopRequest(string $request_id): void
|
||||
{
|
||||
unset($this->caches[$request_id]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use GET请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function headers($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): array
|
||||
{
|
||||
//
|
||||
$rid = self::getInstance()->startRequest();
|
||||
//
|
||||
Log::debug("[HEADERS#$rid] $url ", $params);
|
||||
//
|
||||
$payload['query'] = count($params) ? $params : [];
|
||||
$payload['allow_redirects'] = false;
|
||||
//
|
||||
$response = self::getInstance()
|
||||
->withClient($rid)
|
||||
->withUrl($rid, $url)
|
||||
->withMethod($rid, 'get')
|
||||
->withHeaders($rid, $os, $headers)
|
||||
->withOptions($rid, $payload, $headers, $timeout)
|
||||
->handle($rid);
|
||||
//
|
||||
self::getInstance()->stopRequest($rid);
|
||||
//
|
||||
Log::debug("[HEADERS#$rid] " . $response->getBody());
|
||||
//
|
||||
return $response->getHeaders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
125
src/Sign/Sign.php
Normal file
125
src/Sign/Sign.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Sign;
|
||||
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
class Sign extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 登录签名
|
||||
* @param array $payload
|
||||
* @return array
|
||||
*/
|
||||
public static function login(array $payload): array
|
||||
{
|
||||
# Android 新
|
||||
$app_key = base64_decode(getDevice('app.bili_a.app_key_n'));
|
||||
$app_secret = base64_decode(getDevice('app.bili_a.secret_key_n'));
|
||||
//
|
||||
$default = [
|
||||
'access_key' => getU('access_token'),
|
||||
'actionKey' => 'appkey',
|
||||
'appkey' => $app_key,
|
||||
'build' => getDevice('app.bili_a.build'),
|
||||
'channel' => getDevice('app.bili_a.channel'),
|
||||
'device' => getDevice('app.bili_a.device'),
|
||||
'mobi_app' => getDevice('app.bili_a.mobi_app'),
|
||||
'platform' => getDevice('app.bili_a.platform'),
|
||||
'ts' => time(),
|
||||
];
|
||||
//
|
||||
$payload = array_merge($payload, $default);
|
||||
return self::getInstance()->encryption($payload, $app_secret);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 登录签名
|
||||
* @param array $payload
|
||||
* @return array
|
||||
*/
|
||||
public static function tv(array $payload): array
|
||||
{
|
||||
# Tv
|
||||
$app_key = base64_decode(getDevice('app.bili_t.app_key'));
|
||||
$app_secret = base64_decode(getDevice('app.bili_t.secret_key'));
|
||||
//
|
||||
$default = [
|
||||
'appkey' => $app_key,
|
||||
'local_id' => 0,
|
||||
'ts' => time(),
|
||||
];
|
||||
//
|
||||
$payload = array_merge($payload, $default);
|
||||
return self::getInstance()->encryption($payload, $app_secret);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 通用签名
|
||||
* @param array $payload
|
||||
* @return array
|
||||
*/
|
||||
public static function common(array $payload): array
|
||||
{
|
||||
# Android 旧
|
||||
$app_key = base64_decode(getDevice('app.bili_a.app_key'));
|
||||
$app_secret = base64_decode(getDevice('app.bili_a.secret_key'));
|
||||
|
||||
$default = [
|
||||
'access_key' => getU('access_token'),
|
||||
'actionKey' => 'appkey',
|
||||
'appkey' => $app_key,
|
||||
'build' => getDevice('app.bili_a.build'),
|
||||
'device' => getDevice('app.bili_a.device'),
|
||||
'mobi_app' => getDevice('app.bili_a.mobi_app'),
|
||||
'platform' => getDevice('app.bili_a.platform'),
|
||||
'ts' => time(),
|
||||
];
|
||||
$payload = array_merge($payload, $default);
|
||||
return self::getInstance()->encryption($payload, $app_secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加密
|
||||
* @param array $payload
|
||||
* @param string $app_secret
|
||||
* @return array
|
||||
*/
|
||||
protected function encryption(array $payload, string $app_secret): array
|
||||
{
|
||||
if (isset($payload['sign'])) {
|
||||
unset($payload['sign']);
|
||||
}
|
||||
ksort($payload);
|
||||
$data = http_build_query($payload);
|
||||
$payload['sign'] = md5($data . $app_secret);
|
||||
return $payload;
|
||||
}
|
||||
|
||||
}
|
||||
69
src/Task/Task.php
Normal file
69
src/Task/Task.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Task;
|
||||
|
||||
use Amp\Loop;
|
||||
use Bhp\Log\Log;
|
||||
use Bhp\Plugin\Plugin;
|
||||
use Bhp\TimeLock\TimeLock;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Throwable;
|
||||
use function Amp\asyncCall;
|
||||
|
||||
class Task extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hook
|
||||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public static function addTask(string $hook, mixed ...$data): void
|
||||
{
|
||||
asyncCall(function () use ($hook, $data) {
|
||||
while (true) {
|
||||
try {
|
||||
Plugin::getInstance()->trigger($hook, ...$data);
|
||||
} catch (Throwable $e) {
|
||||
// TODO 多次错误删除tasks_***.json文件
|
||||
$error_msg = "MSG: {$e->getMessage()} CODE: {$e->getCode()} FILE: {$e->getFile()} LINE: {$e->getLine()}";
|
||||
Log::error($error_msg);
|
||||
// Notice::push('error', $error_msg);
|
||||
}
|
||||
yield TimeLock::Delayed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function execTasks(): void
|
||||
{
|
||||
Loop::run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
195
src/TimeLock/TimeLock.php
Normal file
195
src/TimeLock/TimeLock.php
Normal file
@ -0,0 +1,195 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\TimeLock;
|
||||
|
||||
use Amp\Delayed;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
class TimeLock extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected ?array $locks = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化时间锁
|
||||
* @param int $times
|
||||
* @param bool $pause
|
||||
* @return void
|
||||
*/
|
||||
public static function initTimeLock(int $times = 0, bool $status = false): void
|
||||
{
|
||||
$class_name = self::getInstance()->getCallClassName();
|
||||
if (!array_key_exists($class_name, self::getInstance()->locks)) {
|
||||
self::getInstance()->locks[$class_name] = ['times' => $times, 'pause' => $status];
|
||||
}
|
||||
print_r(self::getInstance()->locks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置暂停状态
|
||||
* @param bool $status
|
||||
* @return void
|
||||
*/
|
||||
public static function setPause(bool $status = false): void
|
||||
{
|
||||
$class_name = self::getInstance()->getCallClassName();
|
||||
self::getInstance()->locks[$class_name]['pause'] = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取暂停状态
|
||||
* @return bool
|
||||
*/
|
||||
public static function getPause(): bool
|
||||
{
|
||||
return self::getInstance()->getLock()['pause'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 设置计时器
|
||||
* @param int $times
|
||||
* @return void
|
||||
*/
|
||||
public static function setTimes(int $times): void
|
||||
{
|
||||
$class_name = self::getInstance()->getCallClassName();
|
||||
self::getInstance()->locks[$class_name]['times'] = time() + $times;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取计时器
|
||||
* @return bool
|
||||
*/
|
||||
public static function getTimes(): int
|
||||
{
|
||||
return self::getInstance()->getLock()['times'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getLock(): array
|
||||
{
|
||||
$class_name = $this->getCallClassName();
|
||||
if (!array_key_exists($class_name, $this->locks)) {
|
||||
failExit("当前类 $class_name 并未初始化时间锁");
|
||||
}
|
||||
return $this->locks[$class_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use used in Amp loop Delayed
|
||||
* @param int $times
|
||||
* @return Delayed
|
||||
*/
|
||||
public static function Delayed(int $times=1000): Delayed
|
||||
{
|
||||
return new Delayed($times);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 定时
|
||||
* @param int $hour 时
|
||||
* @param int $minute 分
|
||||
* @param int $seconds 秒
|
||||
* @param bool $random 随机一个小时内
|
||||
* @return int
|
||||
*/
|
||||
public static function timing(int $hour, int $minute = 0, int $seconds = 0, bool $random = false): int
|
||||
{
|
||||
$time = strtotime('today') + ($hour * 60 * 60) + ($minute * 60) + ($seconds);
|
||||
if ($time > time()) {
|
||||
$timing = strtotime('today') + ($hour * 60 * 60) + ($minute * 60) + ($seconds) - time();
|
||||
} else {
|
||||
$timing = strtotime('tomorrow') + ($hour * 60 * 60) + ($minute * 60) + ($seconds) - time();
|
||||
}
|
||||
return $random ? $timing + mt_rand(1, 60) * 60 : $timing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 判断是否在时间内
|
||||
* @param string $first_time
|
||||
* @param string $second_time
|
||||
* @return bool
|
||||
*/
|
||||
public static function inTime(string $first_time, string $second_time): bool
|
||||
{
|
||||
#判断当前时间是否在时间段内,如果是,则执行
|
||||
$Day = date('Y-m-d ', time());
|
||||
$timeBegin = strtotime($Day . $first_time);
|
||||
$timeEnd = strtotime($Day . $second_time);
|
||||
$curr_time = time();
|
||||
if ($curr_time >= $timeBegin && $curr_time <= $timeEnd) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取调用者类名
|
||||
* @param int $index
|
||||
* @return string
|
||||
*/
|
||||
protected function getCallClassName(): string
|
||||
{
|
||||
// basename(str_replace('\\', '/', __CLASS__));
|
||||
$backtraces = debug_backtrace();
|
||||
$temp = pathinfo(basename($backtraces[1]['file']))['filename'];
|
||||
//
|
||||
if ($temp == basename(str_replace('\\', '/', __CLASS__))){
|
||||
return pathinfo(basename($backtraces[2]['file']))['filename'];
|
||||
}else{
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取基础CLASS NAME
|
||||
* @return string
|
||||
*/
|
||||
protected function getBaseClass(): string
|
||||
{
|
||||
return basename(str_replace('\\', '/', __CLASS__));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @use 暂停
|
||||
// */
|
||||
// public static function pauseLock(): void
|
||||
// {
|
||||
// // 备份几种获取方式 get_called_class()
|
||||
// // basename(str_replace('\\', '/', $class));
|
||||
// // substr(strrchr($class, "\\"), 1);
|
||||
// // substr($class, strrpos($class, '\\') + 1);
|
||||
// // array_pop(explode('\\', $class));
|
||||
//// Schedule::triggerRefused((new ReflectionClass(static::class))->getShortName());
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
52
src/User/User.php
Normal file
52
src/User/User.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\User;
|
||||
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
class User extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 转换信息
|
||||
* @return array
|
||||
*/
|
||||
#[ArrayShape(['csrf' => "mixed|string", 'uid' => "mixed|string", 'sid' => "mixed|string"])]
|
||||
public static function parseCookie(): array
|
||||
{
|
||||
$cookies = getU('cookie');
|
||||
preg_match('/bili_jct=(.{32})/', $cookies, $token);
|
||||
preg_match('/DedeUserID=(\d+)/', $cookies, $uid);
|
||||
preg_match('/DedeUserID__ckMd5=(.{16})/', $cookies, $sid);
|
||||
return [
|
||||
'csrf' => $token[1] ?? '',
|
||||
'uid' => $uid[1] ?? '',
|
||||
'sid' => $sid[1] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
42
src/Util/ArrayR/ArrayR.php
Normal file
42
src/Util/ArrayR/ArrayR.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\ArrayR;
|
||||
|
||||
class ArrayR
|
||||
{
|
||||
/**
|
||||
* @use 关联数组转字符串
|
||||
* @param array $arr
|
||||
* @param string $sep1
|
||||
* @param string $sep2
|
||||
* @return string
|
||||
*/
|
||||
public static function toStr(array $arr, string $sep1 = ':', string $sep2 = '\r\n'): string
|
||||
{
|
||||
$tmp = '';
|
||||
foreach ($arr as $key => $value) {
|
||||
$tmp .= "$key$sep1$value$sep2";
|
||||
}
|
||||
return $tmp;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,28 +1,21 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Tool;
|
||||
namespace Bhp\Util\Common;
|
||||
|
||||
class Common
|
||||
{
|
||||
@ -85,7 +78,17 @@ class Common
|
||||
return $newStr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 检查手机号格式
|
||||
* @param string $phone
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkPhone(string $phone): bool
|
||||
{
|
||||
// /^1[3456789]{1}\d{9}$/
|
||||
if (!preg_match("/^1[3456789]\d{9}$/", $phone)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
89
src/Util/DesignPattern/SingleTon.php
Normal file
89
src/Util/DesignPattern/SingleTon.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\DesignPattern;
|
||||
|
||||
class SingleTon
|
||||
{
|
||||
|
||||
/**
|
||||
* @use 创建静态私有的变量保存该类对象
|
||||
* @var array|null
|
||||
*/
|
||||
private static ?array $_instances = [];
|
||||
|
||||
/**
|
||||
* @use SingleTon constructor. 私有的构造方法|防止使用new直接创建对象
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 创建__clone方法防止对象被复制克隆
|
||||
* @return void
|
||||
*/
|
||||
private function __clone(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 放置反序列化
|
||||
* @return void
|
||||
*/
|
||||
public function __wakeup(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param bool $overwrite
|
||||
* @return void
|
||||
*/
|
||||
protected static function addInstance(string $className, bool $overwrite = false): void
|
||||
{
|
||||
if (isset(self::$_instances[$className]) && !$overwrite) {
|
||||
throw new \InvalidArgumentException($className);
|
||||
}
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \InvalidArgumentException($className);
|
||||
}
|
||||
|
||||
$instance = new $className();
|
||||
|
||||
self::$_instances[$className] = $instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed ...$params
|
||||
* @return static
|
||||
*/
|
||||
public static function getInstance(mixed...$params): self
|
||||
{
|
||||
$className = static::class;
|
||||
if (!isset(self::$_instances[$className])) {
|
||||
self::addInstance($className);
|
||||
// test
|
||||
if (is_callable([self::$_instances[$className], 'init'])) {
|
||||
self::$_instances[$className]->init(...$params);
|
||||
}
|
||||
}
|
||||
return self::$_instances[$className];
|
||||
}
|
||||
}
|
||||
@ -1,40 +1,34 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Script;
|
||||
namespace Bhp\Util\Exceptions;
|
||||
|
||||
use BiliHelper\Core\Log;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class DelDynamic extends BaseTask
|
||||
class GetConfigException extends Exception
|
||||
{
|
||||
public static string $description = '批量删除动态,默认单次最大清理300个动态.';
|
||||
|
||||
/**
|
||||
* @use run
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public static function run()
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
Log::error('当前功能未完成');
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
34
src/Util/Exceptions/HttpClientInitException.php
Normal file
34
src/Util/Exceptions/HttpClientInitException.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class HttpClientInitException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
36
src/Util/Exceptions/MethodNotFoundException.php
Normal file
36
src/Util/Exceptions/MethodNotFoundException.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class MethodNotFoundException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,43 +1,34 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Plugins\Example;
|
||||
namespace Bhp\Util\Exceptions;
|
||||
|
||||
use BiliHelper\Plugins\Plugins;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class Example
|
||||
class ResponseEmptyException extends Exception
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
$Manager = Plugins::getInstance();
|
||||
$Manager->register('Example', $this, 'example');
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
|
||||
public function example($example): string
|
||||
{
|
||||
return "插件" . $example;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
@ -6,13 +6,42 @@
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
* Source: https://github.com/anhao/bv2av/
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Tool;
|
||||
namespace Bhp\Util\Fake;
|
||||
|
||||
class Generator
|
||||
class Fake
|
||||
{
|
||||
/**
|
||||
* @use 生成UUID
|
||||
* @return string
|
||||
*/
|
||||
public static function uuid(): string
|
||||
{
|
||||
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
// 48 bits for "node"
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 生成uuid4
|
||||
* @return string
|
||||
@ -24,7 +53,7 @@ class Generator
|
||||
// var e = 16 * Math.random() | 0;
|
||||
// return ("x" === t ? e : 3 & e | 8).toString(16)
|
||||
// });
|
||||
$chars = md5(uniqid(mt_rand(), true));
|
||||
$chars = md5(uniqid((string)mt_rand(), true));
|
||||
$chars = substr_replace($chars, "4", 12, 1);
|
||||
$chars = substr_replace($chars, "a", 16, 1);
|
||||
return substr($chars, 0, 8) . '-'
|
||||
@ -46,7 +75,6 @@ class Generator
|
||||
return md5($content); // sha1
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 生成BUVID
|
||||
* @return string
|
||||
@ -5,11 +5,11 @@
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
* Updated: 2021 ~ 2022
|
||||
* Source: https://github.com/fzaninotto/Faker/
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Tool;
|
||||
namespace Bhp\Util\Fake;
|
||||
|
||||
class Faker
|
||||
{
|
||||
59
src/Util/Os/Path.php
Normal file
59
src/Util/Os/Path.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Os;
|
||||
|
||||
class Path
|
||||
{
|
||||
/**
|
||||
* @use Folder Permissions
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
* @return void
|
||||
* 0600 所有者可读写,其他人没有任何权限
|
||||
* 0644 所有者可读写,其他人可读
|
||||
* 0755 所有者有所有权限,其他所有人可读和执行
|
||||
* 0740 所有者有所有权限,所有者所在的组可读
|
||||
* 0777 所有权限
|
||||
*/
|
||||
public static function SetFolderPermissions(string $path, int $permissions = 0777): void
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
chmod($path, $permissions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Create Folder
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
* @return void
|
||||
* 0600 所有者可读写,其他人没有任何权限
|
||||
* 0644 所有者可读写,其他人可读
|
||||
* 0755 所有者有所有权限,其他所有人可读和执行
|
||||
* 0740 所有者有所有权限,所有者所在的组可读
|
||||
* 0777 所有权限
|
||||
*/
|
||||
public static function CreateFolder(string $path, int $permissions = 0777): void
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path, $permissions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
59
src/Util/Qrcode/Lib/Constants.php
Normal file
59
src/Util/Qrcode/Lib/Constants.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class Constants
|
||||
{
|
||||
const QR_CACHEABLE = false;
|
||||
const QR_CACHE_DIR = ''; //dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
|
||||
const QR_FIND_BEST_MASK = true;
|
||||
const QR_FIND_FROM_RANDOM = false;
|
||||
const QR_DEFAULT_MASK = 2;
|
||||
|
||||
// Encoding modes
|
||||
const QR_MODE_NUL = -1;
|
||||
const QR_MODE_NUM = 0;
|
||||
const QR_MODE_AN = 1;
|
||||
const QR_MODE_8 = 2;
|
||||
const QR_MODE_KANJI = 3;
|
||||
const QR_MODE_STRUCTURE = 4;
|
||||
|
||||
// Levels of error correction.
|
||||
const QR_ECLEVEL_L = 0;
|
||||
const QR_ECLEVEL_M = 1;
|
||||
const QR_ECLEVEL_Q = 2;
|
||||
const QR_ECLEVEL_H = 3;
|
||||
|
||||
// Supported output formats
|
||||
const STRUCTURE_HEADER_BITS = 20;
|
||||
const MAX_STRUCTURED_SYMBOLS = 16;
|
||||
|
||||
// Maks
|
||||
const N1 = 3;
|
||||
const N2 = 3;
|
||||
const N3 = 40;
|
||||
const N4 = 10;
|
||||
|
||||
const QRSPEC_VERSION_MAX = 40;
|
||||
const QRSPEC_WIDTH_MAX = 177;
|
||||
|
||||
const QRCAP_WIDTH = 0;
|
||||
const QRCAP_WORDS = 1;
|
||||
const QRCAP_REMINDER = 2;
|
||||
const QRCAP_EC = 3;
|
||||
}
|
||||
117
src/Util/Qrcode/Lib/FrameFiller.php
Normal file
117
src/Util/Qrcode/Lib/FrameFiller.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class FrameFiller
|
||||
{
|
||||
public int $width;
|
||||
public array $frame;
|
||||
public int $x;
|
||||
public int $y;
|
||||
public int $dir;
|
||||
public int $bit;
|
||||
|
||||
/**
|
||||
* @param $width
|
||||
* @param $frame
|
||||
*/
|
||||
public function __construct($width, &$frame)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->frame = $frame;
|
||||
$this->x = $width - 1;
|
||||
$this->y = $width - 1;
|
||||
$this->dir = -1;
|
||||
$this->bit = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $at
|
||||
* @param int $val
|
||||
* @return void
|
||||
*/
|
||||
public function setFrameAt(array $at, int $val): void
|
||||
{
|
||||
$this->frame[$at['y']][$at['x']] = chr($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $at
|
||||
* @return int
|
||||
*/
|
||||
public function getFrameAt(array $at): int
|
||||
{
|
||||
return ord($this->frame[$at['y']][$at['x']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function next(): ?array
|
||||
{
|
||||
do {
|
||||
if ($this->bit == -1) {
|
||||
$this->bit = 0;
|
||||
return array('x' => $this->x, 'y' => $this->y);
|
||||
}
|
||||
|
||||
$x = $this->x;
|
||||
$y = $this->y;
|
||||
$w = $this->width;
|
||||
|
||||
if ($this->bit == 0) {
|
||||
$x--;
|
||||
$this->bit++;
|
||||
} else {
|
||||
$x++;
|
||||
$y += $this->dir;
|
||||
$this->bit--;
|
||||
}
|
||||
|
||||
if ($this->dir < 0) {
|
||||
if ($y < 0) {
|
||||
$y = 0;
|
||||
$x -= 2;
|
||||
$this->dir = 1;
|
||||
if ($x == 6) {
|
||||
$x--;
|
||||
$y = 9;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($y == $w) {
|
||||
$y = $w - 1;
|
||||
$x -= 2;
|
||||
$this->dir = -1;
|
||||
if ($x == 6) {
|
||||
$x--;
|
||||
$y -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($x < 0 || $y < 0) return null;
|
||||
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
|
||||
} while (ord($this->frame[$y][$x]) & 0x80);
|
||||
|
||||
return array('x' => $x, 'y' => $y);
|
||||
}
|
||||
|
||||
}
|
||||
200
src/Util/Qrcode/Lib/QrBitStream.php
Normal file
200
src/Util/Qrcode/Lib/QrBitStream.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrBitStream
|
||||
{
|
||||
|
||||
public array $data = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function size(): int
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $setLength
|
||||
* @return int
|
||||
*/
|
||||
public function allocate(int $setLength): int
|
||||
{
|
||||
$this->data = array_fill(0, $setLength, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
* @param int $num
|
||||
* @return QrBitStream
|
||||
*/
|
||||
public static function newFromNum(int $bits, int $num): QrBitStream
|
||||
{
|
||||
$bstream = new QrBitStream();
|
||||
$bstream->allocate($bits);
|
||||
|
||||
$mask = 1 << ($bits - 1);
|
||||
for ($i = 0; $i < $bits; $i++) {
|
||||
if ($num & $mask) {
|
||||
$bstream->data[$i] = 1;
|
||||
} else {
|
||||
$bstream->data[$i] = 0;
|
||||
}
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
* @param array $data
|
||||
* @return QrBitStream
|
||||
*/
|
||||
public static function newFromBytes(int $size, array $data): QrBitStream
|
||||
{
|
||||
$bstream = new QrBitStream();
|
||||
$bstream->allocate($size * 8);
|
||||
$p = 0;
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$mask = 0x80;
|
||||
for ($j = 0; $j < 8; $j++) {
|
||||
if ($data[$i] & $mask) {
|
||||
$bstream->data[$p] = 1;
|
||||
} else {
|
||||
$bstream->data[$p] = 0;
|
||||
}
|
||||
$p++;
|
||||
$mask = $mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QrBitStream $arg
|
||||
* @return int
|
||||
*/
|
||||
public function append(QrBitStream $arg): int
|
||||
{
|
||||
if (is_null($arg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($arg->size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->size() == 0) {
|
||||
$this->data = $arg->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->data = array_values(array_merge($this->data, $arg->data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bits
|
||||
* @param int $num
|
||||
* @return int
|
||||
*/
|
||||
public function appendNum(int $bits, int $num): int
|
||||
{
|
||||
if ($bits == 0)
|
||||
return 0;
|
||||
|
||||
$b = QrBitStream::newFromNum($bits, $num);
|
||||
|
||||
if (is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
* @param array $data
|
||||
* @return int
|
||||
*/
|
||||
public function appendBytes(int $size, array $data): int
|
||||
{
|
||||
if ($size == 0)
|
||||
return 0;
|
||||
|
||||
$b = QrBitStream::newFromBytes($size, $data);
|
||||
|
||||
if (is_null($b))
|
||||
return -1;
|
||||
|
||||
$ret = $this->append($b);
|
||||
unset($b);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toByte(): array
|
||||
{
|
||||
|
||||
$size = $this->size();
|
||||
|
||||
if ($size == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = array_fill(0, (int)(($size + 7) / 8), 0);
|
||||
$bytes = (int)($size / 8);
|
||||
|
||||
$p = 0;
|
||||
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
$v = 0;
|
||||
for ($j = 0; $j < 8; $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$i] = $v;
|
||||
}
|
||||
|
||||
if ($size & 7) {
|
||||
$v = 0;
|
||||
for ($j = 0; $j < ($size & 7); $j++) {
|
||||
$v = $v << 1;
|
||||
$v |= $this->data[$p];
|
||||
$p++;
|
||||
}
|
||||
$data[$bytes] = $v;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
164
src/Util/Qrcode/Lib/QrCode.php
Normal file
164
src/Util/Qrcode/Lib/QrCode.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrCode
|
||||
{
|
||||
|
||||
public int $version;
|
||||
public int $width;
|
||||
public array $data;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeMask(QrInput $input, $mask)
|
||||
{
|
||||
if ($input->getVersion() < 0 || $input->getVersion() > Constants::QRSPEC_VERSION_MAX) {
|
||||
throw new Exception('wrong version');
|
||||
}
|
||||
if ($input->getErrorCorrectionLevel() > Constants::QR_ECLEVEL_H) {
|
||||
throw new Exception('wrong level');
|
||||
}
|
||||
|
||||
$raw = new QrRawCode($input);
|
||||
|
||||
$version = $raw->version;
|
||||
$width = QrSpec::getWidth($version);
|
||||
$frame = QrSpec::newFrame($version);
|
||||
|
||||
$filler = new FrameFiller($width, $frame);
|
||||
if (is_null($filler)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// inteleaved data and ecc codes
|
||||
for ($i = 0; $i < $raw->dataLength + $raw->eccLength; $i++) {
|
||||
$code = $raw->getCode();
|
||||
$bit = 0x80;
|
||||
for ($j = 0; $j < 8; $j++) {
|
||||
$addr = $filler->next();
|
||||
$filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
|
||||
$bit = $bit >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
unset($raw);
|
||||
|
||||
// remainder bits
|
||||
$j = QrSpec::getRemainder($version);
|
||||
for ($i = 0; $i < $j; $i++) {
|
||||
$addr = $filler->next();
|
||||
$filler->setFrameAt($addr, 0x02);
|
||||
}
|
||||
|
||||
$frame = $filler->frame;
|
||||
unset($filler);
|
||||
|
||||
|
||||
// masking
|
||||
$maskObj = new QrMask();
|
||||
if ($mask < 0) {
|
||||
|
||||
if (Constants::QR_FIND_BEST_MASK) {
|
||||
$masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
|
||||
} else {
|
||||
$masked = $maskObj->makeMask($width, $frame, (intval(Constants::QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
|
||||
}
|
||||
} else {
|
||||
$masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
|
||||
}
|
||||
|
||||
if ($masked == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
$this->version = $version;
|
||||
$this->width = $width;
|
||||
$this->data = $masked;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeInput(QrInput $input)
|
||||
{
|
||||
return $this->encodeMask($input, -1);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeString8bit($string, $version, $level)
|
||||
{
|
||||
if ($string == NULL) {
|
||||
throw new Exception('empty string!');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$input = new QrInput($version, $level);
|
||||
if ($input == NULL) return NULL;
|
||||
|
||||
$ret = $input->append($input, Constants::QR_MODE_8, strlen($string), str_split($string));
|
||||
if ($ret < 0) {
|
||||
unset($input);
|
||||
return NULL;
|
||||
}
|
||||
return $this->encodeInput($input);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeString($string, $version, $level, $hint, $case_sensitive)
|
||||
{
|
||||
|
||||
if ($hint != Constants::QR_MODE_8 && $hint != Constants::QR_MODE_KANJI) {
|
||||
throw new Exception('bad hint');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$input = new QrInput($version, $level);
|
||||
if ($input == NULL) return NULL;
|
||||
|
||||
$ret = QrSplit::splitStringToQrInput($string, $input, $hint, $case_sensitive);
|
||||
if ($ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $this->encodeInput($input);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function png($text, $outfile = false, $level = Constants::QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint = false)
|
||||
{
|
||||
$enc = QrEncode::factory($level, $size, $margin);
|
||||
return $enc->encodePNG($text, $outfile, $saveandprint);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function text($text, $outfile = false, $level = Constants::QR_ECLEVEL_L, $size = 3, $margin = 4)
|
||||
{
|
||||
$enc = QrEncode::factory($level, $size, $margin);
|
||||
return $enc->encode($text, $outfile);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function raw($text, $outfile = false, $level = Constants::QR_ECLEVEL_L, $size = 3, $margin = 4)
|
||||
{
|
||||
$enc = QrEncode::factory($level, $size, $margin);
|
||||
return $enc->encodeRAW($text, $outfile);
|
||||
}
|
||||
}
|
||||
76
src/Util/Qrcode/Lib/QrEncode.php
Normal file
76
src/Util/Qrcode/Lib/QrEncode.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrEncode
|
||||
{
|
||||
public bool $case_sensitive = true;
|
||||
public bool $eight_bit = false;
|
||||
|
||||
public int $version = 0;
|
||||
public int $size = 3;
|
||||
public int $margin = 4;
|
||||
|
||||
public int $structured = 0; // not supported yet
|
||||
|
||||
public int $level = Constants::QR_ECLEVEL_L;
|
||||
public int $hint = Constants::QR_MODE_8;
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
* @param int $size
|
||||
* @param int $margin
|
||||
* @return QrEncode
|
||||
*/
|
||||
public static function factory(int $level = Constants::QR_ECLEVEL_L, int $size = 3, int $margin = 4): QrEncode
|
||||
{
|
||||
$enc = new QrEncode();
|
||||
$enc->size = $size;
|
||||
$enc->margin = $margin;
|
||||
|
||||
$enc->level = match ($level . '') {
|
||||
'0', '1', '2', '3' => $level,
|
||||
'l', 'L' => Constants::QR_ECLEVEL_L,
|
||||
'm', 'M' => Constants::QR_ECLEVEL_M,
|
||||
'q', 'Q' => Constants::QR_ECLEVEL_Q,
|
||||
'h', 'H' => Constants::QR_ECLEVEL_H,
|
||||
};
|
||||
return $enc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function encode(string $text): array
|
||||
{
|
||||
$code = new QrCode();
|
||||
|
||||
if ($this->eight_bit) {
|
||||
$code->encodeString8bit($text, $this->version, $this->level);
|
||||
} else {
|
||||
$code->encodeString($text, $this->version, $this->level, $this->hint, $this->case_sensitive);
|
||||
}
|
||||
|
||||
return QrTools::binarize($code->data);
|
||||
}
|
||||
|
||||
}
|
||||
89
src/Util/Qrcode/Lib/QrImage.php
Normal file
89
src/Util/Qrcode/Lib/QrImage.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrImage
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4, $saveandprint = FALSE)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
} else {
|
||||
if ($saveandprint === TRUE) {
|
||||
ImagePng($image, $filename);
|
||||
header("Content-type: image/png");
|
||||
ImagePng($image);
|
||||
} else {
|
||||
ImagePng($image, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85)
|
||||
{
|
||||
$image = self::image($frame, $pixelPerPoint, $outerFrame);
|
||||
|
||||
if ($filename === false) {
|
||||
Header("Content-type: image/jpeg");
|
||||
ImageJpeg($image, null, $q);
|
||||
} else {
|
||||
ImageJpeg($image, $filename, $q);
|
||||
}
|
||||
|
||||
ImageDestroy($image);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function image($frame, $pixelPerPoint = 4, $outerFrame = 4)
|
||||
{
|
||||
$h = count($frame);
|
||||
$w = strlen($frame[0]);
|
||||
|
||||
$imgW = $w + 2 * $outerFrame;
|
||||
$imgH = $h + 2 * $outerFrame;
|
||||
|
||||
$base_image = ImageCreate($imgW, $imgH);
|
||||
|
||||
$col[0] = ImageColorAllocate($base_image, 255, 255, 255);
|
||||
$col[1] = ImageColorAllocate($base_image, 0, 0, 0);
|
||||
|
||||
imagefill($base_image, 0, 0, $col[0]);
|
||||
|
||||
for ($y = 0; $y < $h; $y++) {
|
||||
for ($x = 0; $x < $w; $x++) {
|
||||
if ($frame[$y][$x] == '1') {
|
||||
ImageSetPixel($base_image, $x + $outerFrame, $y + $outerFrame, $col[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$target_image = ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
|
||||
ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
|
||||
ImageDestroy($base_image);
|
||||
|
||||
return $target_image;
|
||||
}
|
||||
}
|
||||
492
src/Util/Qrcode/Lib/QrInput.php
Normal file
492
src/Util/Qrcode/Lib/QrInput.php
Normal file
@ -0,0 +1,492 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrInput
|
||||
{
|
||||
public ?array $items;
|
||||
private int $version;
|
||||
private int $level;
|
||||
|
||||
/**
|
||||
* @param int $version
|
||||
* @param int $level
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(int $version = 0, int $level = Constants::QR_ECLEVEL_L)
|
||||
{
|
||||
if ($version < 0 || $version > Constants::QRSPEC_VERSION_MAX || $level > Constants::QR_ECLEVEL_H) {
|
||||
throw new Exception('Invalid version no');
|
||||
}
|
||||
$this->version = $version;
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getVersion(): int
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $version
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setVersion(int $version): void
|
||||
{
|
||||
if ($version < 0 || $version > Constants::QRSPEC_VERSION_MAX) {
|
||||
throw new Exception('Invalid version no');
|
||||
}
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getErrorCorrectionLevel(): int
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $level
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setErrorCorrectionLevel($level): void
|
||||
{
|
||||
if ($level > Constants::QR_ECLEVEL_H) {
|
||||
throw new Exception('Invalid ECLEVEL');
|
||||
}
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QrInputItem $entry
|
||||
* @return void
|
||||
*/
|
||||
public function appendEntry(QrInputItem $entry): void
|
||||
{
|
||||
$this->items[] = $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $mode
|
||||
* @param $size
|
||||
* @param $data
|
||||
* @return int
|
||||
*/
|
||||
public function append($mode, $size, $data)
|
||||
{
|
||||
try {
|
||||
$entry = new QrInputItem($mode, $size, $data);
|
||||
$this->items[] = $entry;
|
||||
return 0;
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
public function insertStructuredAppendHeader($size, $index, $parity)
|
||||
{
|
||||
if ($size > Constants::MAX_STRUCTURED_SYMBOLS) {
|
||||
throw new Exception('insertStructuredAppendHeader wrong size');
|
||||
}
|
||||
|
||||
if ($index <= 0 || $index > Constants::MAX_STRUCTURED_SYMBOLS) {
|
||||
throw new Exception('insertStructuredAppendHeader wrong index');
|
||||
}
|
||||
|
||||
$buf = array($size, $index, $parity);
|
||||
|
||||
try {
|
||||
$entry = new QrInputItem(Constants::QR_MODE_STRUCTURE, 3, buf);
|
||||
array_unshift($this->items, $entry);
|
||||
return 0;
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function calcParity()
|
||||
{
|
||||
$parity = 0;
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
if ($item->mode != Constants::QR_MODE_STRUCTURE) {
|
||||
for ($i = $item->size - 1; $i >= 0; $i--) {
|
||||
$parity ^= $item->data[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $parity;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function checkModeNum($size, $data)
|
||||
{
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
if ((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function estimateBitsModeNum($size)
|
||||
{
|
||||
$w = (int)$size / 3;
|
||||
$bits = $w * 10;
|
||||
|
||||
switch ($size - $w * 3) {
|
||||
case 1:
|
||||
$bits += 4;
|
||||
break;
|
||||
case 2:
|
||||
$bits += 7;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static $anTable = array(
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function lookAnTable($c)
|
||||
{
|
||||
return (($c > 127) ? -1 : self::$anTable[$c]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function checkModeAn($size, $data)
|
||||
{
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
if (self::lookAnTable(ord($data[$i])) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function estimateBitsModeAn($size)
|
||||
{
|
||||
$w = (int)($size / 2);
|
||||
$bits = $w * 11;
|
||||
|
||||
if ($size & 1) {
|
||||
$bits += 6;
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function estimateBitsMode8($size)
|
||||
{
|
||||
return $size * 8;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function estimateBitsModeKanji($size)
|
||||
{
|
||||
return (int)(($size / 2) * 13);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function checkModeKanji($size, $data)
|
||||
{
|
||||
if ($size & 1)
|
||||
return false;
|
||||
|
||||
for ($i = 0; $i < $size; $i += 2) {
|
||||
$val = (ord($data[$i]) << 8) | ord($data[$i + 1]);
|
||||
if ($val < 0x8140
|
||||
|| ($val > 0x9ffc && $val < 0xe040)
|
||||
|| $val > 0xebbf) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Validation
|
||||
**********************************************************************/
|
||||
|
||||
public static function check($mode, $size, $data)
|
||||
{
|
||||
if ($size <= 0)
|
||||
return false;
|
||||
|
||||
switch ($mode) {
|
||||
case Constants::QR_MODE_NUM:
|
||||
return self::checkModeNum($size, $data);
|
||||
case Constants::QR_MODE_AN:
|
||||
return self::checkModeAn($size, $data);
|
||||
case Constants::QR_MODE_KANJI:
|
||||
return self::checkModeKanji($size, $data);
|
||||
case Constants::QR_MODE_STRUCTURE:
|
||||
case Constants::QR_MODE_8:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function estimateBitStreamSize($version)
|
||||
{
|
||||
$bits = 0;
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
$bits += $item->estimateBitStreamSizeOfEntry($version);
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function estimateVersion()
|
||||
{
|
||||
$version = 0;
|
||||
$prev = 0;
|
||||
do {
|
||||
$prev = $version;
|
||||
$bits = $this->estimateBitStreamSize($prev);
|
||||
$version = QrSpec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
|
||||
if ($version < 0) {
|
||||
return -1;
|
||||
}
|
||||
} while ($version > $prev);
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function lengthOfCode($mode, $version, $bits)
|
||||
{
|
||||
$payload = $bits - 4 - QrSpec::lengthIndicator($mode, $version);
|
||||
switch ($mode) {
|
||||
case Constants::QR_MODE_NUM:
|
||||
$chunks = (int)($payload / 10);
|
||||
$remain = $payload - $chunks * 10;
|
||||
$size = $chunks * 3;
|
||||
if ($remain >= 7) {
|
||||
$size += 2;
|
||||
} else if ($remain >= 4) {
|
||||
$size += 1;
|
||||
}
|
||||
break;
|
||||
case Constants::QR_MODE_AN:
|
||||
$chunks = (int)($payload / 11);
|
||||
$remain = $payload - $chunks * 11;
|
||||
$size = $chunks * 2;
|
||||
if ($remain >= 6)
|
||||
$size++;
|
||||
break;
|
||||
case Constants::QR_MODE_8:
|
||||
$size = (int)($payload / 8);
|
||||
break;
|
||||
case Constants::QR_MODE_KANJI:
|
||||
$size = (int)(($payload / 13) * 2);
|
||||
break;
|
||||
case Constants::QR_MODE_STRUCTURE:
|
||||
$size = (int)($payload / 8);
|
||||
break;
|
||||
default:
|
||||
$size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
$maxsize = QrSpec::maximumWords($mode, $version);
|
||||
if ($size < 0) $size = 0;
|
||||
if ($size > $maxsize) $size = $maxsize;
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function createBitStream()
|
||||
{
|
||||
$total = 0;
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
$bits = $item->encodeBitStream($this->version);
|
||||
|
||||
if ($bits < 0)
|
||||
return -1;
|
||||
|
||||
$total += $bits;
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function convertData()
|
||||
{
|
||||
$ver = $this->estimateVersion();
|
||||
if ($ver > $this->getVersion()) {
|
||||
$this->setVersion($ver);
|
||||
}
|
||||
|
||||
for (; ;) {
|
||||
$bits = $this->createBitStream();
|
||||
|
||||
if ($bits < 0)
|
||||
return -1;
|
||||
|
||||
$ver = QrSpec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
|
||||
if ($ver < 0) {
|
||||
throw new Exception('WRONG VERSION');
|
||||
return -1;
|
||||
} else if ($ver > $this->getVersion()) {
|
||||
$this->setVersion($ver);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function appendPaddingBit(&$bstream)
|
||||
{
|
||||
$bits = $bstream->size();
|
||||
$maxwords = QrSpec::getDataLength($this->version, $this->level);
|
||||
$maxbits = $maxwords * 8;
|
||||
|
||||
if ($maxbits == $bits) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($maxbits - $bits < 5) {
|
||||
return $bstream->appendNum($maxbits - $bits, 0);
|
||||
}
|
||||
|
||||
$bits += 4;
|
||||
$words = (int)(($bits + 7) / 8);
|
||||
|
||||
$padding = new QrBitStream();
|
||||
$ret = $padding->appendNum($words * 8 - $bits + 4, 0);
|
||||
|
||||
if ($ret < 0)
|
||||
return $ret;
|
||||
|
||||
$padlen = $maxwords - $words;
|
||||
|
||||
if ($padlen > 0) {
|
||||
|
||||
$padbuf = [];
|
||||
for ($i = 0; $i < $padlen; $i++) {
|
||||
$padbuf[$i] = ($i & 1) ? 0x11 : 0xec;
|
||||
}
|
||||
|
||||
$ret = $padding->appendBytes($padlen, $padbuf);
|
||||
|
||||
if ($ret < 0)
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
$ret = $bstream->append($padding);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mergeBitStream()
|
||||
{
|
||||
if ($this->convertData() < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bstream = new QrBitStream();
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
$ret = $bstream->append($item->bstream);
|
||||
if ($ret < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function getBitStream()
|
||||
{
|
||||
|
||||
$bstream = $this->mergeBitStream();
|
||||
|
||||
if ($bstream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$ret = $this->appendPaddingBit($bstream);
|
||||
if ($ret < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function getByteStream()
|
||||
{
|
||||
$bstream = $this->getBitStream();
|
||||
if ($bstream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $bstream->toByte();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
280
src/Util/Qrcode/Lib/QrInputItem.php
Normal file
280
src/Util/Qrcode/Lib/QrInputItem.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrInputItem
|
||||
{
|
||||
public $mode;
|
||||
public $size;
|
||||
public $data;
|
||||
public $bstream;
|
||||
|
||||
public function __construct($mode, $size, $data, $bstream = null)
|
||||
{
|
||||
$setData = array_slice($data, 0, $size);
|
||||
|
||||
if (count($setData) < $size) {
|
||||
$setData = array_merge($setData, array_fill(0, $size - count($setData), 0));
|
||||
}
|
||||
|
||||
if (!QrInput::check($mode, $size, $setData)) {
|
||||
throw new Exception('Error m:' . $mode . ',s:' . $size . ',d:' . join(',', $setData));
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->size = $size;
|
||||
$this->data = $setData;
|
||||
$this->bstream = $bstream;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeModeNum($version)
|
||||
{
|
||||
try {
|
||||
|
||||
$words = (int)($this->size / 3);
|
||||
$bs = new QrBitStream();
|
||||
|
||||
$val = 0x1;
|
||||
$bs->appendNum(4, $val);
|
||||
$bs->appendNum(QrSpec::lengthIndicator(Constants::QR_MODE_NUM, $version), $this->size);
|
||||
|
||||
for ($i = 0; $i < $words; $i++) {
|
||||
$val = (ord($this->data[$i * 3]) - ord('0')) * 100;
|
||||
$val += (ord($this->data[$i * 3 + 1]) - ord('0')) * 10;
|
||||
$val += (ord($this->data[$i * 3 + 2]) - ord('0'));
|
||||
$bs->appendNum(10, $val);
|
||||
}
|
||||
|
||||
if ($this->size - $words * 3 == 1) {
|
||||
$val = ord($this->data[$words * 3]) - ord('0');
|
||||
$bs->appendNum(4, $val);
|
||||
} else if ($this->size - $words * 3 == 2) {
|
||||
$val = (ord($this->data[$words * 3]) - ord('0')) * 10;
|
||||
$val += (ord($this->data[$words * 3 + 1]) - ord('0'));
|
||||
$bs->appendNum(7, $val);
|
||||
}
|
||||
|
||||
$this->bstream = $bs;
|
||||
return 0;
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeModeAn($version)
|
||||
{
|
||||
try {
|
||||
$words = (int)($this->size / 2);
|
||||
$bs = new QrBitStream();
|
||||
|
||||
$bs->appendNum(4, 0x02);
|
||||
$bs->appendNum(QrSpec::lengthIndicator(Constants::QR_MODE_AN, $version), $this->size);
|
||||
|
||||
for ($i = 0; $i < $words; $i++) {
|
||||
$val = (int)QrInput::lookAnTable(ord($this->data[$i * 2])) * 45;
|
||||
$val += (int)QrInput::lookAnTable(ord($this->data[$i * 2 + 1]));
|
||||
|
||||
$bs->appendNum(11, $val);
|
||||
}
|
||||
|
||||
if ($this->size & 1) {
|
||||
$val = QrInput::lookAnTable(ord($this->data[$words * 2]));
|
||||
$bs->appendNum(6, $val);
|
||||
}
|
||||
|
||||
$this->bstream = $bs;
|
||||
return 0;
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeMode8($version)
|
||||
{
|
||||
try {
|
||||
$bs = new QrBitStream();
|
||||
|
||||
$bs->appendNum(4, 0x4);
|
||||
$bs->appendNum(QrSpec::lengthIndicator(Constants::QR_MODE_8, $version), $this->size);
|
||||
|
||||
for ($i = 0; $i < $this->size; $i++) {
|
||||
$bs->appendNum(8, ord($this->data[$i]));
|
||||
}
|
||||
|
||||
$this->bstream = $bs;
|
||||
return 0;
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeModeKanji($version)
|
||||
{
|
||||
try {
|
||||
|
||||
$bs = new QrBitStream();
|
||||
|
||||
$bs->appendNum(4, 0x8);
|
||||
$bs->appendNum(QrSpec::lengthIndicator(Constants::QR_MODE_KANJI, $version), (int)($this->size / 2));
|
||||
|
||||
for ($i = 0; $i < $this->size; $i += 2) {
|
||||
$val = (ord($this->data[$i]) << 8) | ord($this->data[$i + 1]);
|
||||
if ($val <= 0x9ffc) {
|
||||
$val -= 0x8140;
|
||||
} else {
|
||||
$val -= 0xc140;
|
||||
}
|
||||
|
||||
$h = ($val >> 8) * 0xc0;
|
||||
$val = ($val & 0xff) + $h;
|
||||
|
||||
$bs->appendNum(13, $val);
|
||||
}
|
||||
|
||||
$this->bstream = $bs;
|
||||
return 0;
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeModeStructure()
|
||||
{
|
||||
try {
|
||||
$bs = new QrBitStream();
|
||||
|
||||
$bs->appendNum(4, 0x03);
|
||||
$bs->appendNum(4, ord($this->data[1]) - 1);
|
||||
$bs->appendNum(4, ord($this->data[0]) - 1);
|
||||
$bs->appendNum(8, ord($this->data[2]));
|
||||
|
||||
$this->bstream = $bs;
|
||||
return 0;
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function estimateBitStreamSizeOfEntry($version)
|
||||
{
|
||||
$bits = 0;
|
||||
|
||||
if ($version == 0)
|
||||
$version = 1;
|
||||
|
||||
switch ($this->mode) {
|
||||
case Constants::QR_MODE_NUM:
|
||||
$bits = QrInput::estimateBitsModeNum($this->size);
|
||||
break;
|
||||
case Constants::QR_MODE_AN:
|
||||
$bits = QrInput::estimateBitsModeAn($this->size);
|
||||
break;
|
||||
case Constants::QR_MODE_8:
|
||||
$bits = QrInput::estimateBitsMode8($this->size);
|
||||
break;
|
||||
case Constants::QR_MODE_KANJI:
|
||||
$bits = QrInput::estimateBitsModeKanji($this->size);
|
||||
break;
|
||||
case Constants::QR_MODE_STRUCTURE:
|
||||
return Constants::STRUCTURE_HEADER_BITS;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
$l = QrSpec::lengthIndicator($this->mode, $version);
|
||||
$m = 1 << $l;
|
||||
$num = (int)(($this->size + $m - 1) / $m);
|
||||
|
||||
$bits += $num * (4 + $l);
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encodeBitStream($version)
|
||||
{
|
||||
try {
|
||||
|
||||
unset($this->bstream);
|
||||
$words = QrSpec::maximumWords($this->mode, $version);
|
||||
|
||||
if ($this->size > $words) {
|
||||
|
||||
$st1 = new QrInputItem($this->mode, $words, $this->data);
|
||||
$st2 = new QrInputItem($this->mode, $this->size - $words, array_slice($this->data, $words));
|
||||
|
||||
$st1->encodeBitStream($version);
|
||||
$st2->encodeBitStream($version);
|
||||
|
||||
$this->bstream = new QrBitStream();
|
||||
$this->bstream->append($st1->bstream);
|
||||
$this->bstream->append($st2->bstream);
|
||||
|
||||
unset($st1);
|
||||
unset($st2);
|
||||
|
||||
} else {
|
||||
|
||||
$ret = 0;
|
||||
|
||||
switch ($this->mode) {
|
||||
case Constants::QR_MODE_NUM:
|
||||
$ret = $this->encodeModeNum($version);
|
||||
break;
|
||||
case Constants::QR_MODE_AN:
|
||||
$ret = $this->encodeModeAn($version);
|
||||
break;
|
||||
case Constants::QR_MODE_8:
|
||||
$ret = $this->encodeMode8($version);
|
||||
break;
|
||||
case Constants::QR_MODE_KANJI:
|
||||
$ret = $this->encodeModeKanji($version);
|
||||
break;
|
||||
case Constants::QR_MODE_STRUCTURE:
|
||||
$ret = $this->encodeModeStructure();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ($ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return $this->bstream->size();
|
||||
|
||||
} catch (Exception $e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
347
src/Util/Qrcode/Lib/QrMask.php
Normal file
347
src/Util/Qrcode/Lib/QrMask.php
Normal file
@ -0,0 +1,347 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrMask
|
||||
{
|
||||
|
||||
public array $runLength = [];
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct()
|
||||
{
|
||||
$this->runLength = array_fill(0, Constants::QRSPEC_WIDTH_MAX + 1, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function writeFormatInformation($width, &$frame, $mask, $level)
|
||||
{
|
||||
$blacks = 0;
|
||||
$format = QrSpec::getFormatInfo($mask, $level);
|
||||
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
if ($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[8][$width - 1 - $i] = chr($v);
|
||||
if ($i < 6) {
|
||||
$frame[$i][8] = chr($v);
|
||||
} else {
|
||||
$frame[$i + 1][8] = chr($v);
|
||||
}
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
if ($format & 1) {
|
||||
$blacks += 2;
|
||||
$v = 0x85;
|
||||
} else {
|
||||
$v = 0x84;
|
||||
}
|
||||
|
||||
$frame[$width - 7 + $i][8] = chr($v);
|
||||
if ($i == 0) {
|
||||
$frame[8][7] = chr($v);
|
||||
} else {
|
||||
$frame[8][6 - $i] = chr($v);
|
||||
}
|
||||
|
||||
$format = $format >> 1;
|
||||
}
|
||||
|
||||
return $blacks;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask0($x, $y)
|
||||
{
|
||||
return ($x + $y) & 1;
|
||||
}
|
||||
|
||||
public function mask1($x, $y)
|
||||
{
|
||||
return ($y & 1);
|
||||
}
|
||||
|
||||
public function mask2($x, $y)
|
||||
{
|
||||
return ($x % 3);
|
||||
}
|
||||
|
||||
public function mask3($x, $y)
|
||||
{
|
||||
return ($x + $y) % 3;
|
||||
}
|
||||
|
||||
public function mask4($x, $y)
|
||||
{
|
||||
return (((int)($y / 2)) + ((int)($x / 3))) & 1;
|
||||
}
|
||||
|
||||
public function mask5($x, $y)
|
||||
{
|
||||
return (($x * $y) & 1) + ($x * $y) % 3;
|
||||
}
|
||||
|
||||
public function mask6($x, $y)
|
||||
{
|
||||
return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
|
||||
}
|
||||
|
||||
public function mask7($x, $y)
|
||||
{
|
||||
return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
private function generateMaskNo($maskNo, $width, $frame)
|
||||
{
|
||||
$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
|
||||
|
||||
for ($y = 0; $y < $width; $y++) {
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
if (ord($frame[$y][$x]) & 0x80) {
|
||||
$bitMask[$y][$x] = 0;
|
||||
} else {
|
||||
$maskFunc = call_user_func(array($this, 'mask' . $maskNo), $x, $y);
|
||||
$bitMask[$y][$x] = ($maskFunc == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $bitMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function serial($bitFrame)
|
||||
{
|
||||
$codeArr = [];
|
||||
|
||||
foreach ($bitFrame as $line)
|
||||
$codeArr[] = join('', $line);
|
||||
|
||||
return gzcompress(join("\n", $codeArr), 9);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function unserial($code)
|
||||
{
|
||||
$codeArr = [];
|
||||
|
||||
$codeLines = explode("\n", gzuncompress($code));
|
||||
foreach ($codeLines as $line)
|
||||
$codeArr[] = str_split($line);
|
||||
|
||||
return $codeArr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false)
|
||||
{
|
||||
$b = 0;
|
||||
$bitMask = [];
|
||||
|
||||
$fileName = Constants::QR_CACHE_DIR . 'mask_' . $maskNo . DIRECTORY_SEPARATOR . 'mask_' . $width . '_' . $maskNo . '.dat';
|
||||
|
||||
if (Constants::QR_CACHEABLE) {
|
||||
if (file_exists($fileName)) {
|
||||
$bitMask = self::unserial(file_get_contents($fileName));
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
|
||||
if (!file_exists(Constants::QR_CACHE_DIR . 'mask_' . $maskNo))
|
||||
mkdir(Constants::QR_CACHE_DIR . 'mask_' . $maskNo);
|
||||
file_put_contents($fileName, self::serial($bitMask));
|
||||
}
|
||||
} else {
|
||||
$bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
|
||||
}
|
||||
|
||||
if ($maskGenOnly)
|
||||
return;
|
||||
|
||||
$d = $s;
|
||||
|
||||
for ($y = 0; $y < $width; $y++) {
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
if ($bitMask[$y][$x] == 1) {
|
||||
$d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
|
||||
}
|
||||
$b += (int)(ord($d[$y][$x]) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function makeMask($width, $frame, $maskNo, $level)
|
||||
{
|
||||
$masked = array_fill(0, $width, str_repeat("\0", $width));
|
||||
$this->makeMaskNo($maskNo, $width, $frame, $masked);
|
||||
$this->writeFormatInformation($width, $masked, $maskNo, $level);
|
||||
|
||||
return $masked;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function calcN1N3($length)
|
||||
{
|
||||
$demerit = 0;
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
|
||||
if ($this->runLength[$i] >= 5) {
|
||||
$demerit += (Constants::N1 + ($this->runLength[$i] - 5));
|
||||
}
|
||||
if ($i & 1) {
|
||||
if (($i >= 3) && ($i < ($length - 2)) && ($this->runLength[$i] % 3 == 0)) {
|
||||
$fact = (int)($this->runLength[$i] / 3);
|
||||
if (($this->runLength[$i - 2] == $fact) &&
|
||||
($this->runLength[$i - 1] == $fact) &&
|
||||
($this->runLength[$i + 1] == $fact) &&
|
||||
($this->runLength[$i + 2] == $fact)) {
|
||||
if (($this->runLength[$i - 3] < 0) || ($this->runLength[$i - 3] >= (4 * $fact))) {
|
||||
$demerit += Constants::N3;
|
||||
} else if ((($i + 3) >= $length) || ($this->runLength[$i + 3] >= (4 * $fact))) {
|
||||
$demerit += Constants::N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function evaluateSymbol($width, $frame)
|
||||
{
|
||||
$head = 0;
|
||||
$demerit = 0;
|
||||
|
||||
for ($y = 0; $y < $width; $y++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
$frameY = $frame[$y];
|
||||
|
||||
if ($y > 0)
|
||||
$frameYM = $frame[$y - 1];
|
||||
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
if (($x > 0) && ($y > 0)) {
|
||||
$b22 = ord($frameY[$x]) & ord($frameY[$x - 1]) & ord($frameYM[$x]) & ord($frameYM[$x - 1]);
|
||||
$w22 = ord($frameY[$x]) | ord($frameY[$x - 1]) | ord($frameYM[$x]) | ord($frameYM[$x - 1]);
|
||||
|
||||
if (($b22 | ($w22 ^ 1)) & 1) {
|
||||
$demerit += Constants::N2;
|
||||
}
|
||||
}
|
||||
if (($x == 0) && (ord($frameY[$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if ($x > 0) {
|
||||
if ((ord($frameY[$x]) ^ ord($frameY[$x - 1])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head + 1);
|
||||
}
|
||||
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
$head = 0;
|
||||
$this->runLength[0] = 1;
|
||||
|
||||
for ($y = 0; $y < $width; $y++) {
|
||||
if ($y == 0 && (ord($frame[$y][$x]) & 1)) {
|
||||
$this->runLength[0] = -1;
|
||||
$head = 1;
|
||||
$this->runLength[$head] = 1;
|
||||
} else if ($y > 0) {
|
||||
if ((ord($frame[$y][$x]) ^ ord($frame[$y - 1][$x])) & 1) {
|
||||
$head++;
|
||||
$this->runLength[$head] = 1;
|
||||
} else {
|
||||
$this->runLength[$head]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$demerit += $this->calcN1N3($head + 1);
|
||||
}
|
||||
|
||||
return $demerit;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function mask($width, $frame, $level)
|
||||
{
|
||||
$minDemerit = PHP_INT_MAX;
|
||||
$bestMaskNum = 0;
|
||||
$bestMask = [];
|
||||
|
||||
$checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
|
||||
|
||||
if (Constants::QR_FIND_FROM_RANDOM !== false) {
|
||||
|
||||
$howManuOut = 8 - (Constants::QR_FIND_FROM_RANDOM % 9);
|
||||
for ($i = 0; $i < $howManuOut; $i++) {
|
||||
$remPos = rand(0, count($checked_masks) - 1);
|
||||
unset($checked_masks[$remPos]);
|
||||
$checked_masks = array_values($checked_masks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$bestMask = $frame;
|
||||
|
||||
foreach ($checked_masks as $i) {
|
||||
$mask = array_fill(0, $width, str_repeat("\0", $width));
|
||||
|
||||
$demerit = 0;
|
||||
$blacks = 0;
|
||||
$blacks = $this->makeMaskNo($i, $width, $frame, $mask);
|
||||
$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
|
||||
$blacks = (int)(100 * $blacks / ($width * $width));
|
||||
$demerit = (int)((int)(abs($blacks - 50) / 5) * Constants::N4);
|
||||
$demerit += $this->evaluateSymbol($width, $mask);
|
||||
|
||||
if ($demerit < $minDemerit) {
|
||||
$minDemerit = $demerit;
|
||||
$bestMask = $mask;
|
||||
$bestMaskNum = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $bestMask;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
}
|
||||
128
src/Util/Qrcode/Lib/QrRawCode.php
Normal file
128
src/Util/Qrcode/Lib/QrRawCode.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrRawCode
|
||||
{
|
||||
public $version;
|
||||
public $datacode = [];
|
||||
public $ecccode = [];
|
||||
public $blocks;
|
||||
public $rsblocks = []; //of RSblock
|
||||
public $count;
|
||||
public $dataLength;
|
||||
public $eccLength;
|
||||
public $b1;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function __construct(QrInput $input)
|
||||
{
|
||||
$spec = array(0, 0, 0, 0, 0);
|
||||
|
||||
$this->datacode = $input->getByteStream();
|
||||
if (is_null($this->datacode)) {
|
||||
throw new Exception('null input string');
|
||||
}
|
||||
|
||||
QrSpec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
|
||||
|
||||
$this->version = $input->getVersion();
|
||||
$this->b1 = QrSpec::rsBlockNum1($spec);
|
||||
$this->dataLength = QrSpec::rsDataLength($spec);
|
||||
$this->eccLength = QrSpec::rsEccLength($spec);
|
||||
$this->ecccode = array_fill(0, $this->eccLength, 0);
|
||||
$this->blocks = QrSpec::rsBlockNum($spec);
|
||||
|
||||
$ret = $this->init($spec);
|
||||
if ($ret < 0) {
|
||||
throw new Exception('block alloc error');
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->count = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function init(array $spec)
|
||||
{
|
||||
$dl = QrSpec::rsDataCodes1($spec);
|
||||
$el = QrSpec::rsEccCodes1($spec);
|
||||
$rs = QrRs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
|
||||
|
||||
|
||||
$blockNo = 0;
|
||||
$dataPos = 0;
|
||||
$eccPos = 0;
|
||||
for ($i = 0; $i < QrSpec::rsBlockNum1($spec); $i++) {
|
||||
$ecc = array_slice($this->ecccode, $eccPos);
|
||||
$this->rsblocks[$blockNo] = new QrRsBlock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
|
||||
$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
|
||||
|
||||
$dataPos += $dl;
|
||||
$eccPos += $el;
|
||||
$blockNo++;
|
||||
}
|
||||
|
||||
if (QrSpec::rsBlockNum2($spec) == 0)
|
||||
return 0;
|
||||
|
||||
$dl = QrSpec::rsDataCodes2($spec);
|
||||
$el = QrSpec::rsEccCodes2($spec);
|
||||
$rs = QrRs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
|
||||
|
||||
if ($rs == NULL) return -1;
|
||||
|
||||
for ($i = 0; $i < QrSpec::rsBlockNum2($spec); $i++) {
|
||||
$ecc = array_slice($this->ecccode, $eccPos);
|
||||
$this->rsblocks[$blockNo] = new QrRsBlock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
|
||||
$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
|
||||
|
||||
$dataPos += $dl;
|
||||
$eccPos += $el;
|
||||
$blockNo++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function getCode()
|
||||
{
|
||||
$ret = null;
|
||||
|
||||
if ($this->count < $this->dataLength) {
|
||||
$row = $this->count % $this->blocks;
|
||||
$col = $this->count / $this->blocks;
|
||||
if ($col >= $this->rsblocks[0]->dataLength) {
|
||||
$row += $this->b1;
|
||||
}
|
||||
$ret = (int) $this->rsblocks[$row]->data[$col];
|
||||
} else if ($this->count < $this->dataLength + $this->eccLength) {
|
||||
$row = ($this->count - $this->dataLength) % $this->blocks;
|
||||
$col = ($this->count - $this->dataLength) / $this->blocks;
|
||||
$ret = $this->rsblocks[$row]->ecc[$col];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
$this->count++;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
44
src/Util/Qrcode/Lib/QrRs.php
Normal file
44
src/Util/Qrcode/Lib/QrRs.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrRs
|
||||
{
|
||||
|
||||
public static array $items = [];
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
foreach (self::$items as $rs) {
|
||||
if ($rs->pad != $pad) continue;
|
||||
if ($rs->nroots != $nroots) continue;
|
||||
if ($rs->mm != $symsize) continue;
|
||||
if ($rs->gfpoly != $gfpoly) continue;
|
||||
if ($rs->fcr != $fcr) continue;
|
||||
if ($rs->prim != $prim) continue;
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
$rs = QrRsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
|
||||
array_unshift(self::$items, $rs);
|
||||
|
||||
return $rs;
|
||||
}
|
||||
}
|
||||
37
src/Util/Qrcode/Lib/QrRsBlock.php
Normal file
37
src/Util/Qrcode/Lib/QrRsBlock.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
|
||||
class QrRsBlock
|
||||
{
|
||||
public $dataLength;
|
||||
public $data = [];
|
||||
public $eccLength;
|
||||
public $ecc = [];
|
||||
|
||||
public function __construct($dl, $data, $el, &$ecc, QrRsItem $rs)
|
||||
{
|
||||
$rs->encode_rs_char($data, $ecc);
|
||||
|
||||
$this->dataLength = $dl;
|
||||
$this->data = $data;
|
||||
$this->eccLength = $el;
|
||||
$this->ecc = $ecc;
|
||||
}
|
||||
}
|
||||
173
src/Util/Qrcode/Lib/QrRsItem.php
Normal file
173
src/Util/Qrcode/Lib/QrRsItem.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrRsItem
|
||||
{
|
||||
|
||||
public $mm; // Bits per symbol
|
||||
public $nn; // Symbols per block (= (1<<mm)-1)
|
||||
public $alpha_to = []; // log lookup table
|
||||
public $index_of = []; // Antilog lookup table
|
||||
public $genpoly = []; // Generator polynomial
|
||||
public $nroots; // Number of generator roots = number of parity symbols
|
||||
public $fcr; // First consecutive root, index form
|
||||
public $prim; // Primitive element, index form
|
||||
public $iprim; // prim-th root of 1, index form
|
||||
public $pad; // Padding bytes in shortened block
|
||||
public $gfpoly;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function modnn($x)
|
||||
{
|
||||
while ($x >= $this->nn) {
|
||||
$x -= $this->nn;
|
||||
$x = ($x >> $this->mm) + ($x & $this->nn);
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)
|
||||
{
|
||||
// Common code for intializing a Reed-Solomon control block (char or int symbols)
|
||||
// Copyright 2004 Phil Karn, KA9Q
|
||||
// May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
|
||||
$rs = null;
|
||||
|
||||
// Check parameter ranges
|
||||
if ($symsize < 0 || $symsize > 8) return $rs;
|
||||
if ($fcr < 0 || $fcr >= (1 << $symsize)) return $rs;
|
||||
if ($prim <= 0 || $prim >= (1 << $symsize)) return $rs;
|
||||
if ($nroots < 0 || $nroots >= (1 << $symsize)) return $rs; // Can't have more roots than symbol values!
|
||||
if ($pad < 0 || $pad >= ((1 << $symsize) - 1 - $nroots)) return $rs; // Too much padding
|
||||
|
||||
$rs = new QrRsItem();
|
||||
$rs->mm = $symsize;
|
||||
$rs->nn = (1 << $symsize) - 1;
|
||||
$rs->pad = $pad;
|
||||
|
||||
$rs->alpha_to = array_fill(0, $rs->nn + 1, 0);
|
||||
$rs->index_of = array_fill(0, $rs->nn + 1, 0);
|
||||
|
||||
// PHP style macro replacement ;)
|
||||
$NN =& $rs->nn;
|
||||
$A0 =& $NN;
|
||||
|
||||
// Generate Galois field lookup tables
|
||||
$rs->index_of[0] = $A0; // log(zero) = -inf
|
||||
$rs->alpha_to[$A0] = 0; // alpha**-inf = 0
|
||||
$sr = 1;
|
||||
|
||||
for ($i = 0; $i < $rs->nn; $i++) {
|
||||
$rs->index_of[$sr] = $i;
|
||||
$rs->alpha_to[$i] = $sr;
|
||||
$sr <<= 1;
|
||||
if ($sr & (1 << $symsize)) {
|
||||
$sr ^= $gfpoly;
|
||||
}
|
||||
$sr &= $rs->nn;
|
||||
}
|
||||
|
||||
if ($sr != 1) {
|
||||
// field generator polynomial is not primitive!
|
||||
$rs = NULL;
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/* Form RS code generator polynomial from its roots */
|
||||
$rs->genpoly = array_fill(0, $nroots + 1, 0);
|
||||
|
||||
$rs->fcr = $fcr;
|
||||
$rs->prim = $prim;
|
||||
$rs->nroots = $nroots;
|
||||
$rs->gfpoly = $gfpoly;
|
||||
|
||||
/* Find prim-th root of 1, used in decoding */
|
||||
for ($iprim = 1; ($iprim % $prim) != 0; $iprim += $rs->nn)
|
||||
; // intentional empty-body loop!
|
||||
|
||||
$rs->iprim = (int)($iprim / $prim);
|
||||
$rs->genpoly[0] = 1;
|
||||
|
||||
for ($i = 0, $root = $fcr * $prim; $i < $nroots; $i++, $root += $prim) {
|
||||
$rs->genpoly[$i + 1] = 1;
|
||||
|
||||
// Multiply rs->genpoly[] by @**(root + x)
|
||||
for ($j = $i; $j > 0; $j--) {
|
||||
if ($rs->genpoly[$j] != 0) {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j - 1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];
|
||||
} else {
|
||||
$rs->genpoly[$j] = $rs->genpoly[$j - 1];
|
||||
}
|
||||
}
|
||||
// rs->genpoly[0] can never be zero
|
||||
$rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];
|
||||
}
|
||||
|
||||
// convert rs->genpoly[] to index form for quicker encoding
|
||||
for ($i = 0; $i <= $nroots; $i++)
|
||||
$rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public function encode_rs_char($data, &$parity)
|
||||
{
|
||||
$MM =& $this->mm;
|
||||
$NN =& $this->nn;
|
||||
$ALPHA_TO =& $this->alpha_to;
|
||||
$INDEX_OF =& $this->index_of;
|
||||
$GENPOLY =& $this->genpoly;
|
||||
$NROOTS =& $this->nroots;
|
||||
$FCR =& $this->fcr;
|
||||
$PRIM =& $this->prim;
|
||||
$IPRIM =& $this->iprim;
|
||||
$PAD =& $this->pad;
|
||||
$A0 =& $NN;
|
||||
|
||||
$parity = array_fill(0, $NROOTS, 0);
|
||||
|
||||
for ($i = 0; $i < ($NN - $NROOTS - $PAD); $i++) {
|
||||
|
||||
$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
|
||||
if ($feedback != $A0) {
|
||||
// feedback term is non-zero
|
||||
|
||||
// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
|
||||
// always be for the polynomials constructed by init_rs()
|
||||
$feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);
|
||||
|
||||
for ($j = 1; $j < $NROOTS; $j++) {
|
||||
$parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS - $j])];
|
||||
}
|
||||
}
|
||||
|
||||
// Shift
|
||||
array_shift($parity);
|
||||
if ($feedback != $A0) {
|
||||
array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);
|
||||
} else {
|
||||
array_push($parity, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
600
src/Util/Qrcode/Lib/QrSpec.php
Normal file
600
src/Util/Qrcode/Lib/QrSpec.php
Normal file
@ -0,0 +1,600 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrSpec
|
||||
{
|
||||
|
||||
public static array $capacity = array(
|
||||
array(0, 0, 0, array(0, 0, 0, 0)),
|
||||
array(21, 26, 0, array(7, 10, 13, 17)), // 1
|
||||
array(25, 44, 7, array(10, 16, 22, 28)),
|
||||
array(29, 70, 7, array(15, 26, 36, 44)),
|
||||
array(33, 100, 7, array(20, 36, 52, 64)),
|
||||
array(37, 134, 7, array(26, 48, 72, 88)), // 5
|
||||
array(41, 172, 7, array(36, 64, 96, 112)),
|
||||
array(45, 196, 0, array(40, 72, 108, 130)),
|
||||
array(49, 242, 0, array(48, 88, 132, 156)),
|
||||
array(53, 292, 0, array(60, 110, 160, 192)),
|
||||
array(57, 346, 0, array(72, 130, 192, 224)), //10
|
||||
array(61, 404, 0, array(80, 150, 224, 264)),
|
||||
array(65, 466, 0, array(96, 176, 260, 308)),
|
||||
array(69, 532, 0, array(104, 198, 288, 352)),
|
||||
array(73, 581, 3, array(120, 216, 320, 384)),
|
||||
array(77, 655, 3, array(132, 240, 360, 432)), //15
|
||||
array(81, 733, 3, array(144, 280, 408, 480)),
|
||||
array(85, 815, 3, array(168, 308, 448, 532)),
|
||||
array(89, 901, 3, array(180, 338, 504, 588)),
|
||||
array(93, 991, 3, array(196, 364, 546, 650)),
|
||||
array(97, 1085, 3, array(224, 416, 600, 700)), //20
|
||||
array(101, 1156, 4, array(224, 442, 644, 750)),
|
||||
array(105, 1258, 4, array(252, 476, 690, 816)),
|
||||
array(109, 1364, 4, array(270, 504, 750, 900)),
|
||||
array(113, 1474, 4, array(300, 560, 810, 960)),
|
||||
array(117, 1588, 4, array(312, 588, 870, 1050)), //25
|
||||
array(121, 1706, 4, array(336, 644, 952, 1110)),
|
||||
array(125, 1828, 4, array(360, 700, 1020, 1200)),
|
||||
array(129, 1921, 3, array(390, 728, 1050, 1260)),
|
||||
array(133, 2051, 3, array(420, 784, 1140, 1350)),
|
||||
array(137, 2185, 3, array(450, 812, 1200, 1440)), //30
|
||||
array(141, 2323, 3, array(480, 868, 1290, 1530)),
|
||||
array(145, 2465, 3, array(510, 924, 1350, 1620)),
|
||||
array(149, 2611, 3, array(540, 980, 1440, 1710)),
|
||||
array(153, 2761, 3, array(570, 1036, 1530, 1800)),
|
||||
array(157, 2876, 0, array(570, 1064, 1590, 1890)), //35
|
||||
array(161, 3034, 0, array(600, 1120, 1680, 1980)),
|
||||
array(165, 3196, 0, array(630, 1204, 1770, 2100)),
|
||||
array(169, 3362, 0, array(660, 1260, 1860, 2220)),
|
||||
array(173, 3532, 0, array(720, 1316, 1950, 2310)),
|
||||
array(177, 3706, 0, array(750, 1372, 2040, 2430)) //40
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param int $version
|
||||
* @param int $level
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getDataLength(int $version, int $level): mixed
|
||||
{
|
||||
return self::$capacity[$version][Constants::QRCAP_WORDS] - self::$capacity[$version][Constants::QRCAP_EC][$level];
|
||||
}
|
||||
|
||||
public static function getECCLength(int $version,int $level)
|
||||
{
|
||||
return self::$capacity[$version][Constants::QRCAP_EC][$level];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function getWidth(int $version)
|
||||
{
|
||||
return self::$capacity[$version][Constants::QRCAP_WIDTH];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function getRemainder(int $version)
|
||||
{
|
||||
return self::$capacity[$version][Constants::QRCAP_REMINDER];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function getMinimumVersion(int $size, int $level)
|
||||
{
|
||||
|
||||
for ($i = 1; $i <= Constants::QRSPEC_VERSION_MAX; $i++) {
|
||||
$words = self::$capacity[$i][Constants::QRCAP_WORDS] - self::$capacity[$i][Constants::QRCAP_EC][$level];
|
||||
if ($words >= $size)
|
||||
return $i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public static $lengthTableBits = array(
|
||||
array(10, 12, 14),
|
||||
array(9, 11, 13),
|
||||
array(8, 16, 16),
|
||||
array(8, 10, 12)
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function lengthIndicator($mode, $version)
|
||||
{
|
||||
if ($mode == Constants::QR_MODE_STRUCTURE)
|
||||
return 0;
|
||||
|
||||
if ($version <= 9) {
|
||||
$l = 0;
|
||||
} else if ($version <= 26) {
|
||||
$l = 1;
|
||||
} else {
|
||||
$l = 2;
|
||||
}
|
||||
|
||||
return self::$lengthTableBits[$mode][$l];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function maximumWords($mode, $version)
|
||||
{
|
||||
if ($mode == Constants::QR_MODE_STRUCTURE)
|
||||
return 3;
|
||||
|
||||
if ($version <= 9) {
|
||||
$l = 0;
|
||||
} else if ($version <= 26) {
|
||||
$l = 1;
|
||||
} else {
|
||||
$l = 2;
|
||||
}
|
||||
|
||||
$bits = self::$lengthTableBits[$mode][$l];
|
||||
$words = (1 << $bits) - 1;
|
||||
|
||||
if ($mode == Constants::QR_MODE_KANJI) {
|
||||
$words *= 2; // the number of bytes is required
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
// Error correction code -----------------------------------------------
|
||||
// Table of the error correction code (Reed-Solomon block)
|
||||
// See Table 12-16 (pp.30-36), JIS X0510:2004.
|
||||
|
||||
public static $eccTable = array(
|
||||
array(array(0, 0), array(0, 0), array(0, 0), array(0, 0)),
|
||||
array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), // 1
|
||||
array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)),
|
||||
array(array(1, 0), array(1, 0), array(2, 0), array(2, 0)),
|
||||
array(array(1, 0), array(2, 0), array(2, 0), array(4, 0)),
|
||||
array(array(1, 0), array(2, 0), array(2, 2), array(2, 2)), // 5
|
||||
array(array(2, 0), array(4, 0), array(4, 0), array(4, 0)),
|
||||
array(array(2, 0), array(4, 0), array(2, 4), array(4, 1)),
|
||||
array(array(2, 0), array(2, 2), array(4, 2), array(4, 2)),
|
||||
array(array(2, 0), array(3, 2), array(4, 4), array(4, 4)),
|
||||
array(array(2, 2), array(4, 1), array(6, 2), array(6, 2)), //10
|
||||
array(array(4, 0), array(1, 4), array(4, 4), array(3, 8)),
|
||||
array(array(2, 2), array(6, 2), array(4, 6), array(7, 4)),
|
||||
array(array(4, 0), array(8, 1), array(8, 4), array(12, 4)),
|
||||
array(array(3, 1), array(4, 5), array(11, 5), array(11, 5)),
|
||||
array(array(5, 1), array(5, 5), array(5, 7), array(11, 7)), //15
|
||||
array(array(5, 1), array(7, 3), array(15, 2), array(3, 13)),
|
||||
array(array(1, 5), array(10, 1), array(1, 15), array(2, 17)),
|
||||
array(array(5, 1), array(9, 4), array(17, 1), array(2, 19)),
|
||||
array(array(3, 4), array(3, 11), array(17, 4), array(9, 16)),
|
||||
array(array(3, 5), array(3, 13), array(15, 5), array(15, 10)), //20
|
||||
array(array(4, 4), array(17, 0), array(17, 6), array(19, 6)),
|
||||
array(array(2, 7), array(17, 0), array(7, 16), array(34, 0)),
|
||||
array(array(4, 5), array(4, 14), array(11, 14), array(16, 14)),
|
||||
array(array(6, 4), array(6, 14), array(11, 16), array(30, 2)),
|
||||
array(array(8, 4), array(8, 13), array(7, 22), array(22, 13)), //25
|
||||
array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)),
|
||||
array(array(8, 4), array(22, 3), array(8, 26), array(12, 28)),
|
||||
array(array(3, 10), array(3, 23), array(4, 31), array(11, 31)),
|
||||
array(array(7, 7), array(21, 7), array(1, 37), array(19, 26)),
|
||||
array(array(5, 10), array(19, 10), array(15, 25), array(23, 25)), //30
|
||||
array(array(13, 3), array(2, 29), array(42, 1), array(23, 28)),
|
||||
array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)),
|
||||
array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)),
|
||||
array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)),
|
||||
array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35
|
||||
array(array(6, 14), array(6, 34), array(46, 10), array(2, 64)),
|
||||
array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)),
|
||||
array(array(4, 18), array(13, 32), array(48, 14), array(42, 32)),
|
||||
array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)),
|
||||
array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// CACHEABLE!!!
|
||||
|
||||
public static function getEccSpec($version, $level, array &$spec)
|
||||
{
|
||||
if (count($spec) < 5) {
|
||||
$spec = array(0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
$b1 = self::$eccTable[$version][$level][0];
|
||||
$b2 = self::$eccTable[$version][$level][1];
|
||||
$data = self::getDataLength($version, $level);
|
||||
$ecc = self::getECCLength($version, $level);
|
||||
|
||||
if ($b2 == 0) {
|
||||
$spec[0] = $b1;
|
||||
$spec[1] = (int)($data / $b1);
|
||||
$spec[2] = (int)($ecc / $b1);
|
||||
$spec[3] = 0;
|
||||
$spec[4] = 0;
|
||||
} else {
|
||||
$spec[0] = $b1;
|
||||
$spec[1] = (int)($data / ($b1 + $b2));
|
||||
$spec[2] = (int)($ecc / ($b1 + $b2));
|
||||
$spec[3] = $b2;
|
||||
$spec[4] = $spec[1] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Alignment pattern ---------------------------------------------------
|
||||
|
||||
// Positions of alignment patterns.
|
||||
// This array includes only the second and the third position of the
|
||||
// alignment patterns. Rest of them can be calculated from the distance
|
||||
// between them.
|
||||
|
||||
// See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
|
||||
|
||||
public static $alignmentPattern = array(
|
||||
array(0, 0),
|
||||
array(0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
|
||||
array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
|
||||
array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15
|
||||
array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20
|
||||
array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25
|
||||
array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30
|
||||
array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35
|
||||
array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40
|
||||
);
|
||||
|
||||
|
||||
/** --------------------------------------------------------------------
|
||||
* Put an alignment marker.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy center coordinate of the pattern
|
||||
*/
|
||||
public static function putAlignmentMarker(array &$frame, $ox, $oy)
|
||||
{
|
||||
$finder = array(
|
||||
"\xa1\xa1\xa1\xa1\xa1",
|
||||
"\xa1\xa0\xa0\xa0\xa1",
|
||||
"\xa1\xa0\xa1\xa0\xa1",
|
||||
"\xa1\xa0\xa0\xa0\xa1",
|
||||
"\xa1\xa1\xa1\xa1\xa1"
|
||||
);
|
||||
|
||||
$yStart = $oy - 2;
|
||||
$xStart = $ox - 2;
|
||||
|
||||
for ($y = 0; $y < 5; $y++) {
|
||||
QrStr::set($frame, $xStart, $yStart + $y, $finder[$y]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function putAlignmentPattern($version, &$frame, $width)
|
||||
{
|
||||
if ($version < 2)
|
||||
return;
|
||||
|
||||
$d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];
|
||||
if ($d < 0) {
|
||||
$w = 2;
|
||||
} else {
|
||||
$w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);
|
||||
}
|
||||
|
||||
if ($w * $w - 3 == 1) {
|
||||
$x = self::$alignmentPattern[$version][0];
|
||||
$y = self::$alignmentPattern[$version][0];
|
||||
self::putAlignmentMarker($frame, $x, $y);
|
||||
return;
|
||||
}
|
||||
|
||||
$cx = self::$alignmentPattern[$version][0];
|
||||
for ($x = 1; $x < $w - 1; $x++) {
|
||||
self::putAlignmentMarker($frame, 6, $cx);
|
||||
self::putAlignmentMarker($frame, $cx, 6);
|
||||
$cx += $d;
|
||||
}
|
||||
|
||||
$cy = self::$alignmentPattern[$version][0];
|
||||
for ($y = 0; $y < $w - 1; $y++) {
|
||||
$cx = self::$alignmentPattern[$version][0];
|
||||
for ($x = 0; $x < $w - 1; $x++) {
|
||||
self::putAlignmentMarker($frame, $cx, $cy);
|
||||
$cx += $d;
|
||||
}
|
||||
$cy += $d;
|
||||
}
|
||||
}
|
||||
|
||||
// Version information pattern -----------------------------------------
|
||||
|
||||
// Version information pattern (BCH coded).
|
||||
// See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
|
||||
|
||||
// size: [Constants::QRSPEC_VERSION_MAX - 6]
|
||||
|
||||
public static $versionPattern = array(
|
||||
0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
|
||||
0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
|
||||
0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
|
||||
0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
|
||||
0x27541, 0x28c69
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function getVersionPattern($version)
|
||||
{
|
||||
if ($version < 7 || $version > Constants::QRSPEC_VERSION_MAX)
|
||||
return 0;
|
||||
|
||||
return self::$versionPattern[$version - 7];
|
||||
}
|
||||
|
||||
// Format information --------------------------------------------------
|
||||
// See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
|
||||
|
||||
public static $formatInfo = array(
|
||||
array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),
|
||||
array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),
|
||||
array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),
|
||||
array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)
|
||||
);
|
||||
|
||||
public static function getFormatInfo($mask, $level)
|
||||
{
|
||||
if ($mask < 0 || $mask > 7)
|
||||
return 0;
|
||||
|
||||
if ($level < 0 || $level > 3)
|
||||
return 0;
|
||||
|
||||
return self::$formatInfo[$level][$mask];
|
||||
}
|
||||
|
||||
// Frame ---------------------------------------------------------------
|
||||
// Cache of initial frames.
|
||||
|
||||
public static $frames = [];
|
||||
|
||||
/** --------------------------------------------------------------------
|
||||
* Put a finder pattern.
|
||||
* @param frame
|
||||
* @param width
|
||||
* @param ox,oy upper-left coordinate of the pattern
|
||||
*/
|
||||
public static function putFinderPattern(&$frame, $ox, $oy)
|
||||
{
|
||||
$finder = array(
|
||||
"\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
|
||||
"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
|
||||
"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
|
||||
"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
|
||||
"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
|
||||
"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
|
||||
"\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
|
||||
);
|
||||
|
||||
for ($y = 0; $y < 7; $y++) {
|
||||
QrStr::set($frame, $ox, $oy + $y, $finder[$y]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
public static function createFrame($version)
|
||||
{
|
||||
$width = self::$capacity[$version][Constants::QRCAP_WIDTH];
|
||||
$frameLine = str_repeat("\0", $width);
|
||||
$frame = array_fill(0, $width, $frameLine);
|
||||
|
||||
// Finder pattern
|
||||
self::putFinderPattern($frame, 0, 0);
|
||||
self::putFinderPattern($frame, $width - 7, 0);
|
||||
self::putFinderPattern($frame, 0, $width - 7);
|
||||
|
||||
// Separator
|
||||
$yOffset = $width - 7;
|
||||
|
||||
for ($y = 0; $y < 7; $y++) {
|
||||
$frame[$y][7] = "\xc0";
|
||||
$frame[$y][$width - 8] = "\xc0";
|
||||
$frame[$yOffset][7] = "\xc0";
|
||||
$yOffset++;
|
||||
}
|
||||
|
||||
$setPattern = str_repeat("\xc0", 8);
|
||||
|
||||
QrStr::set($frame, 0, 7, $setPattern);
|
||||
QrStr::set($frame, $width - 8, 7, $setPattern);
|
||||
QrStr::set($frame, 0, $width - 8, $setPattern);
|
||||
|
||||
// Format info
|
||||
$setPattern = str_repeat("\x84", 9);
|
||||
QrStr::set($frame, 0, 8, $setPattern);
|
||||
QrStr::set($frame, $width - 8, 8, $setPattern, 8);
|
||||
|
||||
$yOffset = $width - 8;
|
||||
|
||||
for ($y = 0; $y < 8; $y++, $yOffset++) {
|
||||
$frame[$y][8] = "\x84";
|
||||
$frame[$yOffset][8] = "\x84";
|
||||
}
|
||||
|
||||
// Timing pattern
|
||||
|
||||
for ($i = 1; $i < $width - 15; $i++) {
|
||||
$frame[6][7 + $i] = chr(0x90 | ($i & 1));
|
||||
$frame[7 + $i][6] = chr(0x90 | ($i & 1));
|
||||
}
|
||||
|
||||
// Alignment pattern
|
||||
self::putAlignmentPattern($version, $frame, $width);
|
||||
|
||||
// Version information
|
||||
if ($version >= 7) {
|
||||
$vinf = self::getVersionPattern($version);
|
||||
|
||||
$v = $vinf;
|
||||
|
||||
for ($x = 0; $x < 6; $x++) {
|
||||
for ($y = 0; $y < 3; $y++) {
|
||||
$frame[($width - 11) + $y][$x] = chr(0x88 | ($v & 1));
|
||||
$v = $v >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
$v = $vinf;
|
||||
for ($y = 0; $y < 6; $y++) {
|
||||
for ($x = 0; $x < 3; $x++) {
|
||||
$frame[$y][$x + ($width - 11)] = chr(0x88 | ($v & 1));
|
||||
$v = $v >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and a little bit...
|
||||
$frame[$width - 8][8] = "\x81";
|
||||
|
||||
return $frame;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $frame
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function serial(int $frame): bool|string
|
||||
{
|
||||
return gzcompress(join("\n", $frame), 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public static function unserial(string $code): array
|
||||
{
|
||||
return explode("\n", gzuncompress($code));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $version
|
||||
* @return array|mixed|string[]|null
|
||||
*/
|
||||
public static function newFrame(int $version): mixed
|
||||
{
|
||||
if ($version < 1 || $version > Constants::QRSPEC_VERSION_MAX)
|
||||
return null;
|
||||
|
||||
if (!isset(self::$frames[$version])) {
|
||||
|
||||
$fileName = Constants::QR_CACHE_DIR . 'frame_' . $version . '.dat';
|
||||
|
||||
if (Constants::QR_CACHEABLE) {
|
||||
if (file_exists($fileName)) {
|
||||
self::$frames[$version] = self::unserial(file_get_contents($fileName));
|
||||
} else {
|
||||
self::$frames[$version] = self::createFrame($version);
|
||||
file_put_contents($fileName, self::serial(self::$frames[$version]));
|
||||
}
|
||||
} else {
|
||||
self::$frames[$version] = self::createFrame($version);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null(self::$frames[$version]))
|
||||
return null;
|
||||
|
||||
return self::$frames[$version];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsBlockNum(array $spec): mixed
|
||||
{
|
||||
return $spec[0] + $spec[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsBlockNum1(array $spec): mixed
|
||||
{
|
||||
return $spec[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsDataCodes1(array $spec): mixed
|
||||
{
|
||||
return $spec[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsEccCodes1(array $spec): mixed
|
||||
{
|
||||
return $spec[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsBlockNum2(array $spec): mixed
|
||||
{
|
||||
return $spec[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsDataCodes2(array $spec): mixed
|
||||
{
|
||||
return $spec[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rsEccCodes2(array $spec): mixed
|
||||
{
|
||||
return $spec[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return float|int
|
||||
*/
|
||||
public static function rsDataLength(array $spec): float|int
|
||||
{
|
||||
return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $spec
|
||||
* @return float|int
|
||||
*/
|
||||
public static function rsEccLength(array $spec): float|int
|
||||
{
|
||||
return ($spec[0] + $spec[3]) * $spec[2];
|
||||
}
|
||||
|
||||
}
|
||||
340
src/Util/Qrcode/Lib/QrSplit.php
Normal file
340
src/Util/Qrcode/Lib/QrSplit.php
Normal file
@ -0,0 +1,340 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class QrSplit
|
||||
{
|
||||
|
||||
public string $data_str = '';
|
||||
public QrInput $input;
|
||||
public int $mode_hint;
|
||||
|
||||
/**
|
||||
* @param string $data_str
|
||||
* @param QrInput $input
|
||||
* @param int $mode_hint
|
||||
*/
|
||||
public function __construct(string $data_str, QrInput $input, int $mode_hint)
|
||||
{
|
||||
$this->data_str = $data_str;
|
||||
$this->input = $input;
|
||||
$this->mode_hint = $mode_hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @param int $pos
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDigit(string $str, int $pos): bool
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return ((ord($str[$pos]) >= ord('0')) && (ord($str[$pos]) <= ord('9')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @param int $pos
|
||||
* @return bool
|
||||
*/
|
||||
public static function isalnumat(string $str, int $pos): bool
|
||||
{
|
||||
if ($pos >= strlen($str))
|
||||
return false;
|
||||
|
||||
return (QrInput::lookAnTable(ord($str[$pos])) >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pos
|
||||
* @return int
|
||||
*/
|
||||
public function identifyMode(int $pos): int
|
||||
{
|
||||
if ($pos >= strlen($this->data_str))
|
||||
return Constants::QR_MODE_NUL;
|
||||
|
||||
$c = $this->data_str[$pos];
|
||||
|
||||
if (self::isDigit($this->data_str, $pos)) {
|
||||
return Constants::QR_MODE_NUM;
|
||||
} else if (self::isalnumat($this->data_str, $pos)) {
|
||||
return Constants::QR_MODE_AN;
|
||||
} else if ($this->mode_hint == Constants::QR_MODE_KANJI) {
|
||||
|
||||
if ($pos + 1 < strlen($this->data_str)) {
|
||||
$d = $this->data_str[$pos + 1];
|
||||
$word = (ord($c) << 8) | ord($d);
|
||||
if (($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
|
||||
return Constants::QR_MODE_KANJI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Constants::QR_MODE_8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function eatNum(): mixed
|
||||
{
|
||||
$ln = QrSpec::lengthIndicator(Constants::QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
while (self::isDigit($this->data_str, $p)) {
|
||||
$p++;
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$mode = $this->identifyMode($p);
|
||||
|
||||
if ($mode == Constants::QR_MODE_8) {
|
||||
$dif = QrInput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QrInput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QrInput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if ($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
if ($mode == Constants::QR_MODE_AN) {
|
||||
$dif = QrInput::estimateBitsModeNum($run) + 4 + $ln
|
||||
+ QrInput::estimateBitsModeAn(1) // + 4 + la
|
||||
- QrInput::estimateBitsModeAn($run + 1);// - 4 - la
|
||||
if ($dif > 0) {
|
||||
return $this->eatAn();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(Constants::QR_MODE_NUM, $run, str_split($this->data_str));
|
||||
if ($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function eatAn(): mixed
|
||||
{
|
||||
$la = QrSpec::lengthIndicator(Constants::QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QrSpec::lengthIndicator(Constants::QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 0;
|
||||
|
||||
while (self::isalnumat($this->data_str, $p)) {
|
||||
if (self::isDigit($this->data_str, $p)) {
|
||||
$q = $p;
|
||||
while (self::isDigit($this->data_str, $q)) {
|
||||
$q++;
|
||||
}
|
||||
|
||||
$dif = QrInput::estimateBitsModeAn($p) // + 4 + la
|
||||
+ QrInput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QrInput::estimateBitsModeAn($q); // - 4 - la
|
||||
|
||||
if ($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
|
||||
if (!self::isalnumat($this->data_str, $p)) {
|
||||
$dif = QrInput::estimateBitsModeAn($run) + 4 + $la
|
||||
+ QrInput::estimateBitsMode8(1) // + 4 + l8
|
||||
- QrInput::estimateBitsMode8($run + 1); // - 4 - l8
|
||||
if ($dif > 0) {
|
||||
return $this->eat8();
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->input->append(Constants::QR_MODE_AN, $run, str_split($this->data_str));
|
||||
if ($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function eatKanji(): int
|
||||
{
|
||||
$p = 0;
|
||||
|
||||
while ($this->identifyMode($p) == Constants::QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
}
|
||||
|
||||
$ret = $this->input->append(Constants::QR_MODE_KANJI, $p, str_split($this->data_str));
|
||||
if ($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function eat8(): mixed
|
||||
{
|
||||
$la = QrSpec::lengthIndicator(Constants::QR_MODE_AN, $this->input->getVersion());
|
||||
$ln = QrSpec::lengthIndicator(Constants::QR_MODE_NUM, $this->input->getVersion());
|
||||
|
||||
$p = 1;
|
||||
$data_strLen = strlen($this->data_str);
|
||||
|
||||
while ($p < $data_strLen) {
|
||||
|
||||
$mode = $this->identifyMode($p);
|
||||
if ($mode == Constants::QR_MODE_KANJI) {
|
||||
break;
|
||||
}
|
||||
if ($mode == Constants::QR_MODE_NUM) {
|
||||
$q = $p;
|
||||
while (self::isDigit($this->data_str, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QrInput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QrInput::estimateBitsModeNum($q - $p) + 4 + $ln
|
||||
- QrInput::estimateBitsMode8($q); // - 4 - l8
|
||||
if ($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else if ($mode == Constants::QR_MODE_AN) {
|
||||
$q = $p;
|
||||
while (self::isalnumat($this->data_str, $q)) {
|
||||
$q++;
|
||||
}
|
||||
$dif = QrInput::estimateBitsMode8($p) // + 4 + l8
|
||||
+ QrInput::estimateBitsModeAn($q - $p) + 4 + $la
|
||||
- QrInput::estimateBitsMode8($q); // - 4 - l8
|
||||
if ($dif < 0) {
|
||||
break;
|
||||
} else {
|
||||
$p = $q;
|
||||
}
|
||||
} else {
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
$run = $p;
|
||||
$ret = $this->input->append(Constants::QR_MODE_8, $run, str_split($this->data_str));
|
||||
|
||||
if ($ret < 0)
|
||||
return -1;
|
||||
|
||||
return $run;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int|void
|
||||
*/
|
||||
public function splitString()
|
||||
{
|
||||
while (strlen($this->data_str) > 0) {
|
||||
if ($this->data_str == '')
|
||||
return 0;
|
||||
|
||||
$mode = $this->identifyMode(0);
|
||||
|
||||
switch ($mode) {
|
||||
case Constants::QR_MODE_NUM:
|
||||
$length = $this->eatNum();
|
||||
break;
|
||||
case Constants::QR_MODE_AN:
|
||||
$length = $this->eatAn();
|
||||
break;
|
||||
case Constants::QR_MODE_KANJI:
|
||||
if ($hint == Constants::QR_MODE_KANJI)
|
||||
$length = $this->eatKanji();
|
||||
else $length = $this->eat8();
|
||||
break;
|
||||
default:
|
||||
$length = $this->eat8();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ($length == 0) return 0;
|
||||
if ($length < 0) return -1;
|
||||
|
||||
$this->data_str = substr($this->data_str, $length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toUpper(): string
|
||||
{
|
||||
$stringLen = strlen($this->data_str);
|
||||
$p = 0;
|
||||
|
||||
while ($p < $stringLen) {
|
||||
$mode = self::identifyMode((int)substr($this->data_str, $p), $this->mode_hint);
|
||||
if ($mode == Constants::QR_MODE_KANJI) {
|
||||
$p += 2;
|
||||
} else {
|
||||
if (ord($this->data_str[$p]) >= ord('a') && ord($this->data_str[$p]) <= ord('z')) {
|
||||
$this->data_str[$p] = chr(ord($this->data_str[$p]) - 32);
|
||||
}
|
||||
$p++;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->data_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $string $string
|
||||
* @param QrInput $input
|
||||
* @param $mode_hint
|
||||
* @param bool $case_sensitive
|
||||
* @return int|void
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function splitStringToQrInput(?string $string, QrInput $input, $mode_hint, bool $case_sensitive = true)
|
||||
{
|
||||
if ($string == '\0' || $string == '') {
|
||||
throw new Exception('empty string!!!');
|
||||
}
|
||||
|
||||
$split = new QrSplit($string, $input, $mode_hint);
|
||||
|
||||
if (!$case_sensitive)
|
||||
$split->toUpper();
|
||||
|
||||
return $split->splitString();
|
||||
}
|
||||
}
|
||||
34
src/Util/Qrcode/Lib/QrStr.php
Normal file
34
src/Util/Qrcode/Lib/QrStr.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrStr
|
||||
{
|
||||
/**
|
||||
* @param array $src_tab
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param string $repl
|
||||
* @param int|bool $replLen
|
||||
* @return void
|
||||
*/
|
||||
public static function set(array &$src_tab, int $x, int $y, string $repl, int|bool $replLen = false): void
|
||||
{
|
||||
$src_tab[$y] = substr_replace($src_tab[$y], ($replLen !== false) ? substr($repl, 0, $replLen) : $repl, $x, ($replLen !== false) ? $replLen : strlen($repl));
|
||||
}
|
||||
}
|
||||
39
src/Util/Qrcode/Lib/QrTools.php
Normal file
39
src/Util/Qrcode/Lib/QrTools.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode\Lib;
|
||||
|
||||
class QrTools
|
||||
{
|
||||
/**
|
||||
* @use 二值化
|
||||
* @param array $frame
|
||||
* @return array
|
||||
*/
|
||||
public static function binarize(array $frame): array
|
||||
{
|
||||
$len = count($frame);
|
||||
foreach ($frame as &$frameLine) {
|
||||
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$frameLine[$i] = (ord($frameLine[$i]) & 1) ? '1' : '0';
|
||||
}
|
||||
}
|
||||
return $frame;
|
||||
}
|
||||
}
|
||||
|
||||
88
src/Util/Qrcode/Qrcode.php
Normal file
88
src/Util/Qrcode/Qrcode.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Qrcode;
|
||||
|
||||
use Bhp\Util\Qrcode\Lib\Qrcode as QrConsole;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
define('QR_CACHEABLE', true); // use cache - more disk reads but less CPU power, masks and format templates are stored there
|
||||
define('QR_CACHE_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR); // used when QR_CACHEABLE === true
|
||||
define('QR_LOG_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); // default error logs dir
|
||||
define('QR_FIND_BEST_MASK', true); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
|
||||
define('QR_FIND_FROM_RANDOM', false); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
|
||||
define('QR_DEFAULT_MASK', 2); // when QR_FIND_BEST_MASK === false
|
||||
define('QR_PNG_MAXIMUM_SIZE', 1024);
|
||||
// Supported output formats
|
||||
define('QR_FORMAT_TEXT', 0);
|
||||
define('QR_FORMAT_PNG', 1);
|
||||
|
||||
class Qrcode
|
||||
{
|
||||
|
||||
/**
|
||||
* show qrCode on console.
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function show(string $text): void
|
||||
{
|
||||
$output = new ConsoleOutput();
|
||||
static::initQrcodeStyle($output);
|
||||
//
|
||||
$pxMap[0] = static::isWin() ? '<whitec>mm</whitec>' : '<whitec> </whitec>';
|
||||
$pxMap[1] = '<blackc> </blackc>';
|
||||
//
|
||||
$text = QrConsole::text($text);
|
||||
$length = strlen($text[0]);
|
||||
$output->write("\n");
|
||||
//
|
||||
foreach ($text as $line) {
|
||||
$output->write($pxMap[0]);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$type = substr($line, $i, 1);
|
||||
$output->write($pxMap[$type]);
|
||||
}
|
||||
$output->writeln($pxMap[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use determine the console is windows or linux.
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isWin(): bool
|
||||
{
|
||||
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* @use init qrCode style.
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
protected static function initQrcodeStyle(OutputInterface $output): void
|
||||
{
|
||||
$style = new OutputFormatterStyle('black', 'black', ['bold']);
|
||||
$output->getFormatter()->setStyle('blackc', $style);
|
||||
$style = new OutputFormatterStyle('white', 'white', ['bold']);
|
||||
$output->getFormatter()->setStyle('whitec', $style);
|
||||
}
|
||||
}
|
||||
3
src/Util/Qrcode/VERSION
Normal file
3
src/Util/Qrcode/VERSION
Normal file
@ -0,0 +1,3 @@
|
||||
aferrandini/phpqrcode
|
||||
1.1.5
|
||||
2012021604
|
||||
154
src/Util/Resource/BaseResource.php
Normal file
154
src/Util/Resource/BaseResource.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Resource;
|
||||
|
||||
use Bhp\Util\Resource\Resource as EResource;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
|
||||
abstract class BaseResource extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @use 配置对象变量
|
||||
* @var EResource
|
||||
*/
|
||||
protected ?Resource $resource = null;
|
||||
|
||||
/**
|
||||
* @use 配置文件名
|
||||
* @var string
|
||||
*/
|
||||
protected string $filename = '';
|
||||
|
||||
/**
|
||||
* @use 配置文件路径
|
||||
* @var string
|
||||
*/
|
||||
protected string $filepath = '';
|
||||
|
||||
/**
|
||||
* @use 最后访问文件时间
|
||||
* @var int
|
||||
*/
|
||||
protected int $last_access = 0;
|
||||
|
||||
/**
|
||||
* @use 解析器
|
||||
* @var string
|
||||
*/
|
||||
protected string $parser = '';
|
||||
|
||||
/**
|
||||
* @use 设置值
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
// 设置
|
||||
$this->resource = $this->resource->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 根据类型获取值
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, mixed $default = null, string $type = 'default'): mixed
|
||||
{
|
||||
// 判断是否被修改,否则重新加载文件
|
||||
if (fileatime($this->filepath) != $this->last_access) {
|
||||
// TODO 此处逻辑好像重复了
|
||||
$this->loadResource($this->filename, $this->parser);
|
||||
}
|
||||
return match ($type) {
|
||||
'int' => $this->resource->getInt($key, $default),
|
||||
'string' => $this->resource->getString($key, $default),
|
||||
'bool' => $this->resource->getBool($key, $default),
|
||||
'array' => $this->resource->getArray($key, $default),
|
||||
default => $this->resource->get($key, $default),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加载资源文件
|
||||
* @param string $filename
|
||||
* @param string $parser
|
||||
* @return void
|
||||
*/
|
||||
protected function loadResource(string $filename, string $parser): void
|
||||
{
|
||||
// 获取
|
||||
$filepath = $this->getFilePath($filename);
|
||||
// 验证
|
||||
$this->validateFile($filepath, $filename);
|
||||
// 加载
|
||||
$resource = (new Resource())->loadF($filepath, $parser);
|
||||
// 赋值
|
||||
$this->saveInfo($filename, $filepath, $parser, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查文件是否存在
|
||||
* @param string $filepath
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
protected function validateFile(string $filepath, string $filename): void
|
||||
{
|
||||
if (!is_file($filepath)) {
|
||||
die("资源文件 $filename 加载失败,请参照文档查看或添加资源文件!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $filepath
|
||||
* @param string $parser
|
||||
* @param Resource $resource
|
||||
* @return void
|
||||
*/
|
||||
protected function saveInfo(string $filename, string $filepath, string $parser, Resource $resource): void
|
||||
{
|
||||
$this->filename = $filename;
|
||||
// dirname($conf_filepath).DIRECTORY_SEPARATOR.$conf_filename;
|
||||
$this->filepath = $filepath;
|
||||
$this->resource = $resource;
|
||||
$this->parser = $parser;
|
||||
$this->updateLastAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 更新最新修改时间
|
||||
* @return void
|
||||
*/
|
||||
protected function updateLastAccess(): void
|
||||
{
|
||||
$this->last_access = fileatime($this->filepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取文件真实路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getFilePath(string $filename): string;
|
||||
|
||||
}
|
||||
153
src/Util/Resource/BaseResourcePoly.php
Normal file
153
src/Util/Resource/BaseResourcePoly.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Resource;
|
||||
|
||||
use Bhp\Util\Resource\Resource as EResource;
|
||||
|
||||
abstract class BaseResourcePoly
|
||||
{
|
||||
/**
|
||||
* @use 配置对象变量
|
||||
* @var EResource
|
||||
*/
|
||||
protected ?Resource $resource = null;
|
||||
|
||||
/**
|
||||
* @use 配置文件名
|
||||
* @var string
|
||||
*/
|
||||
protected string $filename = '';
|
||||
|
||||
/**
|
||||
* @use 配置文件路径
|
||||
* @var string
|
||||
*/
|
||||
protected string $filepath = '';
|
||||
|
||||
/**
|
||||
* @use 最后访问文件时间
|
||||
* @var int
|
||||
*/
|
||||
protected int $last_access = 0;
|
||||
|
||||
/**
|
||||
* @use 解析器
|
||||
* @var string
|
||||
*/
|
||||
protected string $parser = '';
|
||||
|
||||
/**
|
||||
* @use 设置值
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
// 设置
|
||||
$this->resource = $this->resource->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 根据类型获取值
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, mixed $default = null, string $type = 'default'): mixed
|
||||
{
|
||||
// 判断是否被修改,否则重新加载文件
|
||||
if (fileatime($this->filepath) != $this->last_access) {
|
||||
// TODO 此处逻辑好像重复了
|
||||
$this->loadResource($this->filename, $this->parser);
|
||||
}
|
||||
return match ($type) {
|
||||
'int' => $this->resource->getInt($key, $default),
|
||||
'string' => $this->resource->getString($key, $default),
|
||||
'bool' => $this->resource->getBool($key, $default),
|
||||
'array' => $this->resource->getArray($key, $default),
|
||||
default => $this->resource->get($key, $default),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加载资源文件
|
||||
* @param string $filename
|
||||
* @param string $parser
|
||||
* @return void
|
||||
*/
|
||||
protected function loadResource(string $filename, string $parser): void
|
||||
{
|
||||
// 获取
|
||||
$filepath = $this->getFilePath($filename);
|
||||
// 验证
|
||||
$this->validateFile($filepath, $filename);
|
||||
// 加载
|
||||
$resource = (new Resource())->loadF($filepath, $parser);
|
||||
// 赋值
|
||||
$this->saveInfo($filename, $filepath, $parser, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查文件是否存在
|
||||
* @param string $filepath
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
protected function validateFile(string $filepath, string $filename): void
|
||||
{
|
||||
if (!is_file($filepath)) {
|
||||
die("资源文件 $filename 加载失败,请参照文档查看或添加资源文件!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $filepath
|
||||
* @param string $parser
|
||||
* @param Resource $resource
|
||||
* @return void
|
||||
*/
|
||||
protected function saveInfo(string $filename, string $filepath, string $parser, Resource $resource): void
|
||||
{
|
||||
$this->filename = $filename;
|
||||
// dirname($conf_filepath).DIRECTORY_SEPARATOR.$conf_filename;
|
||||
$this->filepath = $filepath;
|
||||
$this->resource = $resource;
|
||||
$this->parser = $parser;
|
||||
$this->updateLastAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 更新最新修改时间
|
||||
* @return void
|
||||
*/
|
||||
protected function updateLastAccess(): void
|
||||
{
|
||||
$this->last_access = fileatime($this->filepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取文件真实路径
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getFilePath(string $filename): string;
|
||||
|
||||
}
|
||||
218
src/Util/Resource/Collection.php
Normal file
218
src/Util/Resource/Collection.php
Normal file
@ -0,0 +1,218 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Resource;
|
||||
|
||||
use RecursiveArrayIterator;
|
||||
use Toolkit\Stdlib\Arr;
|
||||
use Traversable;
|
||||
use function is_array;
|
||||
use function serialize;
|
||||
use function strpos;
|
||||
use function unserialize;
|
||||
|
||||
/**
|
||||
* Class Collection -> https://github.com/phppkg/config
|
||||
*
|
||||
* @package PhpPkg\Config
|
||||
*
|
||||
* 支持 链式的子节点 设置 和 值获取
|
||||
* e.g:
|
||||
* ```
|
||||
* $data = [
|
||||
* 'foo' => [
|
||||
* 'bar' => [
|
||||
* 'yoo' => 'value'
|
||||
* ]
|
||||
* ]
|
||||
* ];
|
||||
* $config = new Collection();
|
||||
* $config->get('foo.bar.yoo')` equals to $data['foo']['bar']['yoo'];
|
||||
* ```
|
||||
*/
|
||||
class Collection extends \Toolkit\Stdlib\Std\Collection
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public int $mergeDepth = 3;
|
||||
|
||||
/**
|
||||
* The key path separator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $keyPathSep = '.';
|
||||
|
||||
/**
|
||||
* set config value by key/path
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function set(string $key, mixed $value): self
|
||||
{
|
||||
if ($this->keyPathSep && strpos($key, $this->keyPathSep) > 0) {
|
||||
Arr::setByPath($this->data, $key, $value, $this->keyPathSep);
|
||||
return $this;
|
||||
}
|
||||
|
||||
return parent::set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
if ($this->keyPathSep && strpos($key, $this->keyPathSep) > 0) {
|
||||
return Arr::getByPath($this->data, $key, $default, $this->keyPathSep);
|
||||
}
|
||||
|
||||
return parent::get($key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(string $key): bool
|
||||
{
|
||||
return $this->get($key) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return $this->exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyPathSep(): string
|
||||
{
|
||||
return $this->keyPathSep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyPathSep
|
||||
*/
|
||||
public function setKeyPathSep(string $keyPathSep): void
|
||||
{
|
||||
$this->keyPathSep = $keyPathSep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|Traversable $data
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function load(array|Traversable $data): self
|
||||
{
|
||||
$this->bindData($this->data, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|Traversable $data
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadData(array|Traversable $data): self
|
||||
{
|
||||
$this->bindData($this->data, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parent
|
||||
* @param array|Traversable $data
|
||||
* @param int $depth
|
||||
*/
|
||||
protected function bindData(array &$parent, array|Traversable $data, int $depth = 1): void
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
if ($value === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($value) && isset($parent[$key]) && is_array($parent[$key])) {
|
||||
if ($depth > $this->mergeDepth) {
|
||||
$parent[$key] = $value;
|
||||
} else {
|
||||
$this->bindData($parent[$key], $value, ++$depth);
|
||||
}
|
||||
} else {
|
||||
$parent[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getKeys(): array
|
||||
{
|
||||
return array_keys($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RecursiveArrayIterator
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new RecursiveArrayIterator($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset an offset in the iterator.
|
||||
*
|
||||
* @param mixed $offset
|
||||
*/
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
$this->set($offset, null);
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->data = unserialize(serialize($this->data), [
|
||||
'allowed_classes' => self::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
62
src/Util/Resource/CollectionInterface.php
Normal file
62
src/Util/Resource/CollectionInterface.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Resource;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Collection Interface
|
||||
*/
|
||||
interface CollectionInterface extends ArrayAccess, Countable, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
public function set(string $key, mixed $value): void;
|
||||
|
||||
public function get(string $key, $default = null): mixed;
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
*/
|
||||
public function replace(array $items): void;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function all(): array;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function remove(string $key): void;
|
||||
|
||||
/**
|
||||
* clear all data
|
||||
*/
|
||||
public function clear(): void;
|
||||
}
|
||||
109
src/Util/Resource/Resource.php
Normal file
109
src/Util/Resource/Resource.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Util\Resource;
|
||||
|
||||
use Grasmash\Expander\Expander;
|
||||
use Grasmash\Expander\Stringifier;
|
||||
use JBZoo\Data\Data;
|
||||
use function JBZoo\Data\data;
|
||||
use function JBZoo\Data\ini;
|
||||
use function JBZoo\Data\phpArray;
|
||||
use function JBZoo\Data\json;
|
||||
use function JBZoo\Data\yml;
|
||||
|
||||
class Resource extends Collection
|
||||
{
|
||||
protected const FORMAT_INI = 'ini';
|
||||
protected const FORMAT_PHP = 'php';
|
||||
protected const FORMAT_YAML = 'yaml';
|
||||
protected const FORMAT_YML = 'yml';
|
||||
protected const FORMAT_JSON = 'json';
|
||||
|
||||
/**
|
||||
* @var Data
|
||||
*/
|
||||
protected Data $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $file_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $parser;
|
||||
|
||||
/**
|
||||
* @use 加载资源文件
|
||||
* @param string|array $file_path
|
||||
* @param string $parser
|
||||
* @return Resource
|
||||
*/
|
||||
public function loadF(string|array $file_path, string $parser): Resource
|
||||
{
|
||||
// 存储文件路径
|
||||
$this->file_path = $file_path;
|
||||
// 存储解析器
|
||||
$this->parser = $parser;
|
||||
// 加载文件
|
||||
$this->config = $this->switchParser($file_path, $parser);
|
||||
// 加载数据
|
||||
$this->reload();
|
||||
//
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 切换解析器
|
||||
* @param string $filepath
|
||||
* @param string $format
|
||||
* @return Data
|
||||
*/
|
||||
protected function switchParser(string $filepath, string $format): Data
|
||||
{
|
||||
return match ($format) {
|
||||
Resource::FORMAT_INI => ini($filepath),
|
||||
Resource::FORMAT_PHP => phpArray($filepath),
|
||||
Resource::FORMAT_YML, Resource::FORMAT_YAML => yml($filepath),
|
||||
Resource::FORMAT_JSON => json($filepath),
|
||||
default => data($filepath),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 清空并重载数据
|
||||
* @return Resource
|
||||
*/
|
||||
protected function reload(): Resource
|
||||
{
|
||||
// 转换一次 ${}
|
||||
$expander = new Expander();
|
||||
$expander->setStringifier(new Stringifier());
|
||||
$expanded = $expander->expandArrayProperties($this->config->getArrayCopy());
|
||||
// 清除数据
|
||||
$this->clear();
|
||||
// 加载数据
|
||||
$this->load($expanded);
|
||||
//
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
234
src/core/App.php
234
src/core/App.php
@ -1,234 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use Throwable;
|
||||
use Amp\Loop;
|
||||
use BiliHelper\Script\BaseTask;
|
||||
|
||||
use function Amp\asyncCall;
|
||||
|
||||
class App
|
||||
{
|
||||
private int $mode = 0;
|
||||
|
||||
/**
|
||||
* App constructor.
|
||||
* @param string $app_path
|
||||
*/
|
||||
public function __construct(string $app_path)
|
||||
{
|
||||
define('APP_MICROSECOND', 1000000);
|
||||
define('APP_CONF_PATH', $app_path . '/conf/');
|
||||
define('APP_DATA_PATH', $app_path . '/data/');
|
||||
define('APP_LOG_PATH', $app_path . '/log/');
|
||||
define('APP_TASK_PATH', $app_path . '/task/');
|
||||
define('APP_CACHE_PATH', $app_path . '/cache/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化数据文件夹
|
||||
* @param int $permissions
|
||||
* @return void
|
||||
*/
|
||||
private function initDataFolder(int $permissions = 0777): void
|
||||
{
|
||||
// log task cache
|
||||
$data_folder = [APP_LOG_PATH, APP_TASK_PATH, APP_CACHE_PATH];
|
||||
foreach ($data_folder as $path) {
|
||||
if (!file_exists($path)) {
|
||||
mkdir($path);
|
||||
chmod($path, $permissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查环境
|
||||
* @return $this
|
||||
*/
|
||||
public function inspect(): App
|
||||
{
|
||||
(new Env())->inspect_configure()->inspect_extension();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加载配置
|
||||
* @param $argv
|
||||
* @return $this
|
||||
*/
|
||||
public function load($argv): App
|
||||
{
|
||||
$this->initDataFolder();
|
||||
$args = (new BCommand($argv))->run();
|
||||
$filename = $args->args()[0] ?? 'user.ini';
|
||||
// 加载配置
|
||||
Config::getInstance()->load($filename);
|
||||
// 加载设备
|
||||
Device::getInstance()->load($filename);
|
||||
// 引导参数
|
||||
$this->selectMode($args);
|
||||
$this->restoreMode($args);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 新任务
|
||||
* @param string $taskName
|
||||
* @param string $dir
|
||||
*/
|
||||
private function newTask(string $taskName, string $dir)
|
||||
{
|
||||
asyncCall(function () use ($taskName, $dir) {
|
||||
while (true) {
|
||||
try {
|
||||
call_user_func(array("BiliHelper\\$dir\\" . $taskName, 'run'), []);
|
||||
} catch (Throwable $e) {
|
||||
// TODO 多次错误删除tasks_***.json文件
|
||||
$error_msg = "MSG: {$e->getMessage()} CODE: {$e->getCode()} FILE: {$e->getFile()} LINE: {$e->getLine()}";
|
||||
Log::error($error_msg);
|
||||
// Notice::push('error', $error_msg);
|
||||
}
|
||||
if ($dir == 'Plugin')
|
||||
yield call_user_func(array("BiliHelper\\$dir\\" . $taskName, 'Delayed'), []);
|
||||
else
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Script模式
|
||||
*/
|
||||
private function script_m()
|
||||
{
|
||||
$scripts = [
|
||||
'UnFollow' => '批量取消关注(暂测试)',
|
||||
'DelDynamic' => '批量清理动态(未完成)'
|
||||
];
|
||||
|
||||
$choice = BaseTask::choice($scripts, 'UnFollow');
|
||||
$this->newTask($choice, 'Script');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use Loop模式
|
||||
*/
|
||||
private function loop_m()
|
||||
{
|
||||
$plugins = [
|
||||
'CheckUpdate',
|
||||
'Login',
|
||||
'Schedule',
|
||||
'MainSite',
|
||||
'DailyBag',
|
||||
'ManGa',
|
||||
'ActivityLottery',
|
||||
'Competition',
|
||||
'DoubleHeart',
|
||||
'DailyTask',
|
||||
'Barrage',
|
||||
'Silver2Coin',
|
||||
'Judge',
|
||||
'GiftSend',
|
||||
'GroupSignIn',
|
||||
'GiftHeart',
|
||||
'SmallHeart',
|
||||
'MaterialObject',
|
||||
'AloneTcpClient',
|
||||
'ZoneTcpClient',
|
||||
'StormRaffle',
|
||||
'GiftRaffle',
|
||||
'PkRaffle',
|
||||
'GuardRaffle',
|
||||
'AnchorRaffle',
|
||||
'AwardRecord',
|
||||
'Forward',
|
||||
'CapsuleLottery',
|
||||
'PolishTheMedal',
|
||||
'VipPrivilege',
|
||||
'BpConsumption',
|
||||
'LiveReservation',
|
||||
// 'Silver', // Abandoned
|
||||
'Statistics',
|
||||
|
||||
];
|
||||
foreach ($plugins as $plugin) {
|
||||
$this->newTask($plugin, 'Plugin');
|
||||
}
|
||||
Loop::run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 选择模式
|
||||
* @param object $args
|
||||
*/
|
||||
private function selectMode(object $args)
|
||||
{
|
||||
// 可能会有其他模式出现 暂定
|
||||
// 0 默认值 默认模式,1 脚本模式 ...
|
||||
if ($args->script) {
|
||||
$this->mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 复位模式
|
||||
* @param object $args
|
||||
*/
|
||||
private function restoreMode(object $args)
|
||||
{
|
||||
// 复位 后期添加其他复位
|
||||
if ($args->restore) {
|
||||
Task::getInstance()->restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 核心运行
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
switch ($this->mode) {
|
||||
case 0:
|
||||
// 默认
|
||||
Log::info('执行Loop模式');
|
||||
$this->loop_m();
|
||||
break;
|
||||
case 1:
|
||||
// 脚本
|
||||
Log::info('执行Script模式');
|
||||
$this->script_m();
|
||||
break;
|
||||
default:
|
||||
Log::error("请检查,没有选定的执行模式");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use Ahc\Cli\Input\Command;
|
||||
use Exception;
|
||||
|
||||
class BCommand
|
||||
{
|
||||
|
||||
private array $argv;
|
||||
|
||||
/**
|
||||
* Command constructor.
|
||||
* @param $argv
|
||||
*/
|
||||
public function __construct($argv)
|
||||
{
|
||||
$this->argv = $argv;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$cli = new Command('BHP-S', 'BHP命令行工具.');
|
||||
$cli->version('0.0.1-dev')
|
||||
->option('-s --script', '执行的Script模式.', null, false)
|
||||
->option('-r --restore', '任务排程复位(暂定).', null, false);
|
||||
try {
|
||||
$args = $cli->parse($this->argv);
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
die('解析命令行参数错误');
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,126 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
* Source: https://github.com/fzaninotto/Faker/
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use BiliHelper\Util\Singleton;
|
||||
use Flintstone\Flintstone;
|
||||
use Overtrue\Pinyin\Pinyin;
|
||||
use Flintstone\Formatter\JsonFormatter;
|
||||
|
||||
|
||||
class Cache
|
||||
{
|
||||
use Singleton;
|
||||
|
||||
private array $caches;
|
||||
private Flintstone $cache;
|
||||
|
||||
// 文档
|
||||
// https://www.xeweb.net/flintstone/documentation/
|
||||
|
||||
/**
|
||||
* @use 加载一个缓存
|
||||
* @param string $classname
|
||||
* @return \BiliHelper\Core\Cache
|
||||
*/
|
||||
private function load(string $classname): static
|
||||
{
|
||||
if (!isset($this->caches[$classname])) {
|
||||
$username = getConf('username', 'login.account');
|
||||
// 判断字符串中是否有中文
|
||||
if (preg_match("/[\x7f-\xff]/", $username)) {
|
||||
$pinyin = new Pinyin(); // 默认
|
||||
$username = $pinyin->permalink($username); // yong-hu-ming
|
||||
}
|
||||
// 如果不存在缓存 初始化 "BHP_username_APP.dat"
|
||||
$this->caches[$classname] = new Flintstone(
|
||||
$this->removeSpecStr('BHP_' . $username . '_' . $classname),
|
||||
[
|
||||
'dir' => APP_CACHE_PATH,
|
||||
'gzip' => true,
|
||||
'formatter' => new JsonFormatter()
|
||||
]
|
||||
);
|
||||
}
|
||||
$this->cache = $this->caches[$classname];
|
||||
return $this;
|
||||
// self::$instance->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取调用链类
|
||||
* @return mixed
|
||||
*/
|
||||
private function backtraceClass(): mixed
|
||||
{
|
||||
// TODO 耦合度过高 需要解耦
|
||||
$backtraces = debug_backtrace();
|
||||
array_shift($backtraces);
|
||||
return pathinfo(basename($backtraces[2]['file']))['filename'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取调用类
|
||||
* @param string $classname
|
||||
* @return $this
|
||||
*/
|
||||
private function getClassObj(string $classname): static
|
||||
{
|
||||
if ($classname == '') {
|
||||
$classname = $this->backtraceClass();
|
||||
}
|
||||
return $this->load($classname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取值
|
||||
* @param string $key
|
||||
* @param string $extra_name
|
||||
* @return mixed
|
||||
*/
|
||||
public function _get(string $key, string $extra_name = ''): mixed
|
||||
{
|
||||
// Get a key
|
||||
// $user = $users->get('bob');
|
||||
// echo 'Bob, your email is ' . $user['email'];
|
||||
return $this->getClassObj($extra_name)->cache->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 写入值
|
||||
* @param string $key
|
||||
* @param $data
|
||||
* @param string $extra_name
|
||||
*/
|
||||
public function _set(string $key, $data, string $extra_name = '')
|
||||
{
|
||||
// Set a key
|
||||
// $users->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
|
||||
$this->getClassObj($extra_name)->cache->set($key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 去除特殊符号
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
private function removeSpecStr(string $data): string
|
||||
{
|
||||
$specs = str_split("-.,:;'*?~`!@#$%^&+=)(<>{}]|\/、");
|
||||
foreach ($specs as $spec) {
|
||||
$data = str_replace($spec, '', $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use BiliHelper\Util\Singleton;
|
||||
use Jelix\IniFile\IniModifier;
|
||||
|
||||
class Config
|
||||
{
|
||||
use Singleton;
|
||||
|
||||
private string|array $load_file;
|
||||
private int|false $last_time;
|
||||
private IniModifier $app_config;
|
||||
private string $config_path;
|
||||
|
||||
|
||||
/**
|
||||
* @use 加载配置
|
||||
* @param string $load_file
|
||||
*/
|
||||
public function load(string $load_file)
|
||||
{
|
||||
$config_path = str_replace("\\", "/", APP_CONF_PATH . $load_file);
|
||||
if (!is_file($config_path)) {
|
||||
die("配置文件 $load_file 加载错误,请参照文档添加配置文件!");
|
||||
}
|
||||
$this->load_file = $load_file;
|
||||
$this->config_path = $config_path;
|
||||
// $config_path = dirname($config_path).DIRECTORY_SEPARATOR.$load_file;
|
||||
$this->app_config = new IniModifier($this->config_path);
|
||||
$this->last_time = fileatime($this->config_path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @use 写入值
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @param int|string $section
|
||||
* @param null $key
|
||||
* @throws \Jelix\IniFile\IniException
|
||||
*/
|
||||
public function _set($name, $value, int|string $section = 0, $key = null)
|
||||
{
|
||||
$this->app_config->setValue($name, $value, $section, $key);
|
||||
$this->app_config->save();
|
||||
// 保存修改时间
|
||||
$this->last_time = fileatime($this->config_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取值
|
||||
* @param $name
|
||||
* @param int|string $section
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function _get($name, int|string $section = 0, $key = null): mixed
|
||||
{
|
||||
// 判断是否被修改 重新加载文件
|
||||
// echo $this->last_time.PHP_EOL;
|
||||
// echo fileatime($this->config_path);
|
||||
if (fileatime($this->config_path) != $this->last_time) {
|
||||
$this->load($this->load_file);
|
||||
}
|
||||
return $this->app_config->getValue($name, $section, $key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
106
src/core/Core.php
Normal file
106
src/core/Core.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & /l、
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、 。 7
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ / \、゙ ~ヽ *
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \ じしf_, )ノ
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*/
|
||||
|
||||
namespace Bhp\Core;
|
||||
|
||||
use Bhp\Console\Console;
|
||||
use Bhp\Util\DesignPattern\SingleTon;
|
||||
use Bhp\Util\Os\Path;
|
||||
|
||||
class Core extends SingleTon
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $global_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $profile_name;
|
||||
|
||||
/**
|
||||
* @param string $global_path
|
||||
* @param string $profile_name
|
||||
* @return void
|
||||
*/
|
||||
public function init(string $global_path, string $profile_name): void
|
||||
{
|
||||
$this->global_path = $global_path;
|
||||
$this->profile_name = $profile_name;
|
||||
// 定义全局常量
|
||||
$this->initSystemConstant();
|
||||
// 初始化全局文件夹
|
||||
$this->initSystemPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化全局常量
|
||||
* @return void
|
||||
*/
|
||||
protected function initSystemConstant(): void
|
||||
{
|
||||
define('APP_MICROSECOND', 1000000);
|
||||
define('APP_RESOURCES_PATH', $this->global_path . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
|
||||
define('APP_PLUGIN_PATH', $this->global_path . DIRECTORY_SEPARATOR . 'plugin' . DIRECTORY_SEPARATOR);
|
||||
// Profile
|
||||
define('PROFILE_CONFIG_PATH', $this->fillPath('config'));
|
||||
define('PROFILE_DEVICE_PATH', $this->fillPath('device'));
|
||||
define('PROFILE_LOG_PATH', $this->fillPath('log'));
|
||||
define('PROFILE_TASK_PATH', $this->fillPath('task'));
|
||||
define('PROFILE_CACHE_PATH', $this->fillPath('cache'));
|
||||
|
||||
// 判断profile/*是否存在存在
|
||||
if (!is_dir(PROFILE_CONFIG_PATH)) {
|
||||
die("加载 {$this->profile_name} 用户文档失败,请检查路径!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 补充目录
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected function fillPath(string $path): string
|
||||
{
|
||||
// */profile/*/*
|
||||
return $this->global_path . DIRECTORY_SEPARATOR . 'profile' . DIRECTORY_SEPARATOR . $this->profile_name . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 初始化系统目录(创建、设置权限)
|
||||
* @return void
|
||||
*/
|
||||
protected function initSystemPath(): void
|
||||
{
|
||||
$system_paths = [
|
||||
PROFILE_CONFIG_PATH,
|
||||
PROFILE_DEVICE_PATH,
|
||||
PROFILE_LOG_PATH,
|
||||
PROFILE_TASK_PATH,
|
||||
PROFILE_CACHE_PATH
|
||||
];
|
||||
foreach ($system_paths as $path) {
|
||||
if (!file_exists($path)) {
|
||||
Path::CreateFolder($path);
|
||||
Path::SetFolderPermissions($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,362 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\Pool;
|
||||
use GuzzleHttp\Client;
|
||||
use BiliHelper\Tool\Generator;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
class Curl
|
||||
{
|
||||
private static Client $client;
|
||||
private static array $async_opt;
|
||||
private static array $results = [];
|
||||
private static array $result = [];
|
||||
private static string $buvid = '';
|
||||
|
||||
/**
|
||||
* @use POST请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function post($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): mixed
|
||||
{
|
||||
Log::debug("POST: $url");
|
||||
$headers = self::getHeaders($os, $headers);
|
||||
$payload['form_params'] = count($params) ? $params : [];
|
||||
$options = self::getClientOpt($payload, $headers, $timeout);
|
||||
$request = self::clientHandle($url, 'post', $options);
|
||||
$body = $request->getBody();
|
||||
Log::debug($body);
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use GET请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): mixed
|
||||
{
|
||||
Log::debug("GET: $url");
|
||||
$headers = self::getHeaders($os, $headers);
|
||||
$payload['query'] = count($params) ? $params : [];
|
||||
$options = self::getClientOpt($payload, $headers, $timeout);
|
||||
$request = self::clientHandle($url, 'get', $options);
|
||||
$body = $request->getBody();
|
||||
Log::debug($body);
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use PUT请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function put($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): mixed
|
||||
{
|
||||
Log::debug("PUT: $url");
|
||||
$headers = self::getHeaders($os, $headers);
|
||||
$payload['json'] = count($params) ? $params : [];
|
||||
$options = self::getClientOpt($payload, $headers, $timeout);
|
||||
$request = self::clientHandle($url, 'post', $options);
|
||||
$body = $request->getBody();
|
||||
Log::debug($body);
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 并发POST请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $tasks
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return array
|
||||
*/
|
||||
public static function async($os, $url, array $tasks = [], array $headers = [], float $timeout = 30.0): array
|
||||
{
|
||||
self::$async_opt = [
|
||||
'tasks' => $tasks,
|
||||
'counter' => 1,
|
||||
'count' => count($tasks),
|
||||
'concurrency' => min(count($tasks), 10)
|
||||
];
|
||||
Log::debug("ASYNC: $url");
|
||||
$headers = self::getHeaders($os, $headers);
|
||||
$requests = function ($total) use ($url, $headers, $tasks, $timeout) {
|
||||
foreach ($tasks as $task) {
|
||||
yield function () use ($url, $headers, $task, $timeout) {
|
||||
$payload['form_params'] = $task['payload'];
|
||||
$options = self::getClientOpt($payload, $headers, $timeout);
|
||||
return self::clientHandle($url, 'postAsync', $options);
|
||||
};
|
||||
}
|
||||
};
|
||||
$pool = new Pool(self::$client, $requests(self::$async_opt['count']), [
|
||||
'concurrency' => self::$async_opt['concurrency'],
|
||||
'fulfilled' => function ($response, $index) {
|
||||
$res = $response->getBody();
|
||||
// Log::notice("启动多线程 {$index}");
|
||||
self::$results[] = [
|
||||
'content' => $res,
|
||||
'source' => self::$async_opt['tasks'][$index]['source']
|
||||
];
|
||||
self::countedAndCheckEnded();
|
||||
},
|
||||
'rejected' => function ($reason, $index) {
|
||||
Log::error("多线程第 $index 个请求失败, ERROR: $reason");
|
||||
self::countedAndCheckEnded();
|
||||
},
|
||||
]);
|
||||
// 开始发送请求
|
||||
$promise = $pool->promise();
|
||||
$promise->wait();
|
||||
return self::getResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 单次请求
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param array $payload
|
||||
* @param array $headers
|
||||
* @param int $timeout
|
||||
* @return false|string|null
|
||||
*/
|
||||
public static function request($method, $url, array $payload = [], array $headers = [], int $timeout = 10): bool|string|null
|
||||
{
|
||||
Log::debug("REQUEST: $url");
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'method' => strtoupper($method),
|
||||
'header' => self::arr2str($headers),
|
||||
'content' => http_build_query($payload),
|
||||
'timeout' => $timeout,
|
||||
),
|
||||
);
|
||||
$result = $url ? @file_get_contents($url, false, stream_context_create($options)) : null;
|
||||
Log::debug($result);
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 计数搭配并发使用
|
||||
*/
|
||||
private static function countedAndCheckEnded()
|
||||
{
|
||||
if (self::$async_opt['counter'] < self::$async_opt['count']) {
|
||||
self::$async_opt['counter']++;
|
||||
return;
|
||||
}
|
||||
// 请求结束
|
||||
self::$async_opt = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 请求中心异常处理
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
private static function clientHandle(string $url, string $method, array $options): mixed
|
||||
{
|
||||
$max_retry = range(1, 40);
|
||||
foreach ($max_retry as $retry) {
|
||||
try {
|
||||
$response = call_user_func_array([self::$client, $method], [$url, $options]);
|
||||
if (is_null($response) or empty($response)) throw new Exception("Value IsEmpty");
|
||||
return $response;
|
||||
} catch (RequestException $e) {
|
||||
// var_dump($e->getRequest());
|
||||
if ($e->hasResponse()) var_dump($e->getResponse());
|
||||
} catch (Exception $e) {
|
||||
// $e->getHandlerContext()
|
||||
// var_dump($e);
|
||||
}
|
||||
Log::warning("Target -> URL: $url METHOD: $method");
|
||||
Log::warning("CURl -> RETRY: $retry ERROR: {$e->getMessage()} ERRNO: {$e->getCode()} STATUS: Waiting for recovery!");
|
||||
sleep(15);
|
||||
}
|
||||
exit('网络异常,超出最大尝试次数,退出程序~');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取请求配置
|
||||
* @param array $add_options
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return array
|
||||
*/
|
||||
private static function getClientOpt(array $add_options, array $headers = [], float $timeout = 30.0): array
|
||||
{
|
||||
self::$client = new Client();
|
||||
$default_options = [
|
||||
'headers' => $headers,
|
||||
'timeout' => $timeout,
|
||||
'http_errors' => false,
|
||||
'verify' => getConf('verify_ssl', 'network.ssl'),
|
||||
];
|
||||
if (getConf('enable', 'network.proxy')) {
|
||||
$default_options['proxy'] = getConf('proxy', 'network.proxy');
|
||||
}
|
||||
return array_merge($default_options, $add_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取Headers
|
||||
* @param string $os
|
||||
* @param array $headers
|
||||
* @return array
|
||||
*/
|
||||
private static function getHeaders(string $os = 'app', array $headers = []): array
|
||||
{
|
||||
if (!self::$buvid) {
|
||||
// 缓存开始 如果存在就赋值 否则默认值
|
||||
if ($temp = getCache('buvid')) {
|
||||
self::$buvid = $temp;
|
||||
} else {
|
||||
self::$buvid = Generator::buvid();
|
||||
}
|
||||
// 缓存结束 需要的数据的放进缓存
|
||||
setCache('buvid', self::$buvid);
|
||||
}
|
||||
|
||||
$app_headers = [
|
||||
'env' => 'prod',
|
||||
'APP-KEY' => 'android',
|
||||
'Buvid' => self::$buvid,
|
||||
'Accept' => '*/*',
|
||||
'Accept-Encoding' => 'gzip',
|
||||
'Accept-Language' => 'zh-cn',
|
||||
'Connection' => 'keep-alive',
|
||||
'User-Agent' => getDevice('device.app_headers.ua'),
|
||||
// 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
// 'User-Agent' => 'Mozilla/5.0 BiliDroid/5.51.1 (bbcallen@gmail.com)',
|
||||
// 'Referer' => 'https://live.bilibili.com/',
|
||||
];
|
||||
$pc_headers = [
|
||||
'Accept' => "application/json, text/plain, */*",
|
||||
'Accept-Encoding' => 'gzip, deflate',
|
||||
'Accept-Language' => "zh-CN,zh;q=0.9",
|
||||
'User-Agent' => getDevice('device.pc_headers.ua'),
|
||||
// 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
// 'Referer' => 'https://live.bilibili.com/',
|
||||
];
|
||||
$other_headers = [
|
||||
'User-Agent' => getDevice('device.other_headers.ua')
|
||||
];
|
||||
$default_headers = ${$os . "_headers"} ?? $other_headers;
|
||||
if (in_array($os, ['app', 'pc']) && getCookie() != "") {
|
||||
$default_headers['Cookie'] = getCookie();
|
||||
}
|
||||
// return self::formatHeaders(array_merge($default_headers, $headers));
|
||||
return array_merge($default_headers, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 数组
|
||||
* @return array
|
||||
*/
|
||||
private static function getResults(): array
|
||||
{
|
||||
$results = self::$results;
|
||||
self::$results = [];
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 关联数组转字符串
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
private static function arr2str(array $array): string
|
||||
{
|
||||
$tmp = '';
|
||||
foreach ($array as $key => $value) {
|
||||
$tmp .= "$key:$value\r\n";
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use GET请求
|
||||
* @param $os
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public static function headers($os, $url, array $params = [], array $headers = [], float $timeout = 30.0): mixed
|
||||
{
|
||||
Log::debug('HEADERS: ' . $url);
|
||||
$headers = self::getHeaders($os, $headers);
|
||||
$payload['query'] = count($params) ? $params : [];
|
||||
$payload['allow_redirects'] = false;
|
||||
$options = self::getClientOpt($payload, $headers, $timeout);
|
||||
$request = self::clientHandle($url, 'get', $options);
|
||||
Log::debug("获取Headers");
|
||||
return $request->getHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 格式化Headers
|
||||
* @param array $headers
|
||||
* @return array
|
||||
*/
|
||||
private static function formatHeaders(array $headers): array
|
||||
{
|
||||
return array_map(function ($k, $v) {
|
||||
return $k . ': ' . $v;
|
||||
}, array_keys($headers), $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 字符串or其他
|
||||
* @return array
|
||||
*/
|
||||
private static function getResult(): array
|
||||
{
|
||||
$result = self::$result;
|
||||
self::$result = [];
|
||||
return array_shift($result);
|
||||
}
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use BiliHelper\Util\Singleton;
|
||||
use Consolidation\Config\Config;
|
||||
use Consolidation\Config\Loader\YamlConfigLoader;
|
||||
use Consolidation\Config\Loader\ConfigProcessor;
|
||||
|
||||
class Device
|
||||
{
|
||||
use Singleton;
|
||||
|
||||
private Config $device;
|
||||
private string $bili_file = 'bili.yaml';
|
||||
private string $device_file = 'device.yaml';
|
||||
|
||||
|
||||
/**
|
||||
* @use 真实路径
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
private function fileRealPath(string $file): string
|
||||
{
|
||||
return APP_CONF_PATH . $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加载配置
|
||||
*/
|
||||
public function load(string $load_file)
|
||||
{
|
||||
// 提前处理 后缀
|
||||
$custom_file = str_replace(strrchr($load_file, "."), "", $load_file) . '_';
|
||||
// 自定义客户端
|
||||
if (is_file($this->fileRealPath($custom_file . $this->bili_file))) {
|
||||
$this->bili_file = $custom_file . $this->bili_file;
|
||||
Log::info('使用自定义' . $this->bili_file);
|
||||
}
|
||||
// 自定义设备
|
||||
if (is_file($this->fileRealPath($custom_file . $this->device_file))) {
|
||||
$this->device_file = $custom_file . $this->device_file;
|
||||
Log::info('使用自定义' . $this->device_file);
|
||||
}
|
||||
// 加载数据
|
||||
$this->device = new Config();
|
||||
$loader = new YamlConfigLoader();
|
||||
$processor = new ConfigProcessor();
|
||||
$files = [$this->bili_file, $this->device_file];
|
||||
// 循环加载
|
||||
foreach ($files as $file) {
|
||||
$processor->extend($loader->load($this->fileRealPath($file)));
|
||||
}
|
||||
$this->device->import($processor->export());
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取值
|
||||
* @param $key
|
||||
* @param null $defaultFallback
|
||||
* @return mixed
|
||||
*/
|
||||
public function _get($key, $defaultFallback = null): mixed
|
||||
{
|
||||
return $this->device->get($key, $defaultFallback);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
101
src/core/Env.php
101
src/core/Env.php
@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use function JBZoo\Data\json;
|
||||
|
||||
class Env
|
||||
{
|
||||
private string $app_name;
|
||||
private string $app_version;
|
||||
private string $app_branch;
|
||||
private string $app_source;
|
||||
|
||||
private string $repository = APP_DATA_PATH . 'latest_version.json';
|
||||
|
||||
|
||||
/**
|
||||
* Env constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
set_time_limit(0);
|
||||
// header("Content-Type:text/html; charset=utf-8");
|
||||
// ini_set('date.timezone', 'Asia/Shanghai');
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
ini_set('display_errors', 'on');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$this->loadJsonData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查扩展
|
||||
*/
|
||||
public function inspect_extension()
|
||||
{
|
||||
$default_extensions = ['curl', 'openssl', 'sockets', 'json', 'zlib', 'mbstring'];
|
||||
foreach ($default_extensions as $extension) {
|
||||
if (!extension_loaded($extension)) {
|
||||
Log::error("检查到项目依赖 $extension 扩展未加载。");
|
||||
Log::error("请在 php.ini中启用 $extension 扩展后重试。");
|
||||
Log::error("程序常见问题请移步 $this->app_source 文档部分查看。");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 检查环境
|
||||
*/
|
||||
public function inspect_configure(): Env
|
||||
{
|
||||
Log::info("欢迎使用 项目: $this->app_name@$this->app_branch 版本: $this->app_version");
|
||||
Log::info("使用说明请移步 $this->app_source 查看");
|
||||
|
||||
if (PHP_SAPI != 'cli') {
|
||||
die("Please run this script from command line .");
|
||||
}
|
||||
// if (version_compare(PHP_VERSION, '7.4.0', '<')) {
|
||||
// die("Please upgrade PHP version > 7.4.0 .");
|
||||
// }
|
||||
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
|
||||
die("Please upgrade PHP version < 8.0.0 .");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 加载本地JSON DATA
|
||||
*/
|
||||
private function loadJsonData()
|
||||
{
|
||||
$conf = json($this->repository);
|
||||
$this->app_name = $conf->get('project', 'BiliHelper-personal');
|
||||
$this->app_version = $conf->get('version', '0.0.0.000000');
|
||||
$this->app_branch = $conf->get('branch', 'master');
|
||||
$this->app_source = $conf->get('source', 'https://github.com/lkeme/BiliHelper-personal');
|
||||
}
|
||||
}
|
||||
@ -1,141 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
use BiliHelper\Core\Cache;
|
||||
use BiliHelper\Core\Config;
|
||||
use BiliHelper\Core\Device;
|
||||
|
||||
/**
|
||||
* @use 配置读取
|
||||
* @param $name
|
||||
* @param int|string $section
|
||||
* @param null $key
|
||||
* @return mixed
|
||||
*/
|
||||
function getConf($name, int|string $section = 0, $key = null): mixed
|
||||
{
|
||||
return Config::getInstance()->_get($name, $section, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 配置写入
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @param int|string $section
|
||||
* @param null $key
|
||||
* @throws \Jelix\IniFile\IniException
|
||||
*/
|
||||
function setConf($name, $value, int|string $section = 0, $key = null)
|
||||
{
|
||||
Config::getInstance()->_set($name, $value, $section, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 开关
|
||||
* @param string $plugin
|
||||
* @param bool $default
|
||||
* @return bool
|
||||
*/
|
||||
function getEnable(string $plugin, bool $default = false): bool
|
||||
{
|
||||
return getConf('enable', $plugin) ?: $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取ACCESS_TOKEN
|
||||
* @return string
|
||||
*/
|
||||
function getAccessToken(): string
|
||||
{
|
||||
return getConf('access_token', 'login.auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取REFRESH_TOKEN
|
||||
* @return string
|
||||
*/
|
||||
function getRefreshToken(): string
|
||||
{
|
||||
return getConf('refresh_token', 'login.auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取COOKIE
|
||||
* @return string
|
||||
*/
|
||||
function getCookie(): string
|
||||
{
|
||||
return getConf('cookie', 'login.auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取UID
|
||||
* @return int
|
||||
*/
|
||||
function getUid(): int
|
||||
{
|
||||
return getConf('uid', 'login.auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取CSRF
|
||||
* @return string
|
||||
*/
|
||||
function getCsrf(): string
|
||||
{
|
||||
return getConf('csrf', 'login.auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 获取设备信息
|
||||
* @param $key
|
||||
* @param null $defaultFallback
|
||||
* @return mixed
|
||||
*/
|
||||
function getDevice($key, $defaultFallback = null): mixed
|
||||
{
|
||||
return Device::getInstance()->_get($key, $defaultFallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 缓存读取
|
||||
* @param string $key
|
||||
* @param string $extra_name
|
||||
* @return mixed
|
||||
*/
|
||||
function getCache(string $key, string $extra_name = ''): mixed
|
||||
{
|
||||
return Cache::getInstance()->_get($key, $extra_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 缓存写入
|
||||
* @param string $key
|
||||
* @param $data
|
||||
* @param string $extra_name
|
||||
*/
|
||||
function setCache(string $key, $data, string $extra_name = '')
|
||||
{
|
||||
Cache::getInstance()->_set($key, $data, $extra_name);
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
* Resource: https://github.com/XcantloadX
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
class HttpClient
|
||||
{
|
||||
// private $ch;
|
||||
// private $ret;
|
||||
// private $form;
|
||||
// private $headers;
|
||||
// private $url;
|
||||
// private $query;
|
||||
//
|
||||
// public function __construct(string $url)
|
||||
// {
|
||||
// $this->ch = curl_init();
|
||||
// $this->url = $url;
|
||||
// curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false); //忽略 HTTPS 证书错误
|
||||
// $this->setUA("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36");
|
||||
// }
|
||||
//
|
||||
// function __destruct()
|
||||
// {
|
||||
// //防止内存泄露
|
||||
// curl_close($this->ch);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 设置UA
|
||||
// * @param string $ua
|
||||
// * @return $this
|
||||
// */
|
||||
// public function setUA(string $ua): HttpClient
|
||||
// {
|
||||
// curl_setopt($this->ch, CURLOPT_USERAGENT, $ua); //设置 UA
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 添加Header
|
||||
// * @param string $header
|
||||
// * @return $this
|
||||
// */
|
||||
// public function addHeader(string $header): HttpClient
|
||||
// {
|
||||
// array_push($this->headers, $header);
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 添加Headers
|
||||
// * @param array $headers
|
||||
// * @return $this
|
||||
// */
|
||||
// public function addHeaders(array $headers): HttpClient
|
||||
// {
|
||||
// foreach ($headers as $key => $value) {
|
||||
// array_push($this->headers, "{$key}: {$value}");
|
||||
// }
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 设置Cookie
|
||||
// * @param string $cookie
|
||||
// * @return $this
|
||||
// */
|
||||
// public function setCookie(string $cookie): HttpClient
|
||||
// {
|
||||
// curl_setopt($this->ch, CURLOPT_COOKIE, $cookie);
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 设置 url 参数
|
||||
// */
|
||||
// public function buildQuery(array $query): HttpClient
|
||||
// {
|
||||
// $this->query = http_build_query($query);
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 自动将 json 文本解码
|
||||
// */
|
||||
// public function asJSON(): object
|
||||
// {
|
||||
// return json_decode($this->ret);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 获取返回结果
|
||||
// */
|
||||
// public function asString(): string
|
||||
// {
|
||||
// return $this->ret;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 构造POST表单
|
||||
// * @param array $form
|
||||
// * @return $this
|
||||
// */
|
||||
// public function buildPostForm(array $form): HttpClient
|
||||
// {
|
||||
// $this->form = http_build_query($form);
|
||||
//
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 发送 Get 请求
|
||||
// */
|
||||
// public function get(): HttpClient
|
||||
// {
|
||||
// curl_setopt($this->ch, CURLOPT_URL, $this->url . "?" . $this->query);
|
||||
// curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); //返回内容储存到变量中
|
||||
// curl_setopt($this->ch, CURLOPT_HEADER, $this->headers);
|
||||
// $this->ret = curl_exec($this->ch);
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @use 发送 POST 请求
|
||||
// * @param string|null $data 要 POST 的数据
|
||||
// * @return \HttpClient
|
||||
// */
|
||||
// public function post(string $data = null): HttpClient
|
||||
// {
|
||||
// curl_setopt($this->ch, CURLOPT_URL, $this->url . "?" . $this->query);
|
||||
// curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); //返回内容储存到变量中
|
||||
// curl_setopt($this->ch, CURLOPT_POST, true); // 发送 POST 请求
|
||||
// curl_setopt($this->ch, CURLOPT_HEADER, $this->headers);
|
||||
// curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
|
||||
// $this->ret = curl_exec($this->ch);
|
||||
// return $this;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * @use POST表单
|
||||
// * @param array $form
|
||||
// * @return $this
|
||||
// */
|
||||
// public function postForm(array $form): HttpClient
|
||||
// {
|
||||
// return $this->post(http_build_query($form));
|
||||
// }
|
||||
}
|
||||
|
||||
///**
|
||||
// * @use HttpClient
|
||||
// * @param string $url
|
||||
// * @return \BiliHelper\Core\HttpClient
|
||||
// */
|
||||
//function newHttp(string $url): HttpClient
|
||||
//{
|
||||
// return new HttpClient($url);
|
||||
//}
|
||||
|
||||
180
src/core/Log.php
180
src/core/Log.php
@ -1,180 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* _____ _ _ _ _ _ _____ _ _____ _____ _____
|
||||
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \
|
||||
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| |
|
||||
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /
|
||||
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \
|
||||
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
|
||||
*
|
||||
* Website: https://mudew.com/
|
||||
* Author: Lkeme
|
||||
* License: The MIT License
|
||||
* Email: Useri@live.cn
|
||||
* Updated: 2022 ~ 2023
|
||||
*
|
||||
* & /l、
|
||||
* (゚、 。 7
|
||||
* \、゙ ~ヽ *
|
||||
* じしf_, )ノ
|
||||
*
|
||||
*/
|
||||
|
||||
namespace BiliHelper\Core;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Bramus\Monolog\Formatter\ColoredLineFormatter;
|
||||
|
||||
class Log
|
||||
{
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* @use 实体
|
||||
*/
|
||||
static public function getLogger()
|
||||
{
|
||||
if (!self::$instance) {
|
||||
self::configureInstance();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 单例
|
||||
*/
|
||||
private static function configureInstance()
|
||||
{
|
||||
$logger = new Logger('BH');
|
||||
$handler = new StreamHandler('php://stdout', getConf('enable', 'debug') ? Logger::DEBUG : Logger::INFO);
|
||||
$handler->setFormatter(new ColoredLineFormatter());
|
||||
$logger->pushHandler($handler);
|
||||
self::$instance = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 前缀
|
||||
* @return string
|
||||
*/
|
||||
private static function prefix(): string
|
||||
{
|
||||
if (getConf('multiple', 'print')) {
|
||||
// return '[' . (getConf('user_identity', 'print') ?? getConf('username', 'login.account')) . ']';
|
||||
return sprintf("[%s]", getConf('user_identity', 'print') ?? getConf('username', 'login.account'));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 写日志
|
||||
* @param $type
|
||||
* @param $message
|
||||
*/
|
||||
private static function writeLog($type, $message)
|
||||
{
|
||||
if (getConf('enable', 'log')) {
|
||||
if ($type == 'DEBUG' && !getConf('enable', 'debug')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filename = APP_LOG_PATH . getConf('username', 'login.account') . ".log";
|
||||
$date = date('[Y-m-d H:i:s] ');
|
||||
$data = $date . ' Log.' . $type . ' ' . $message . PHP_EOL;
|
||||
file_put_contents($filename, $data, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 堆栈
|
||||
* @return string
|
||||
*/
|
||||
private static function backtrace(): string
|
||||
{
|
||||
$backtraces = debug_backtrace();
|
||||
return "(" . pathinfo(basename($backtraces[1]['file']))['filename'] . ") => ";
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 调试
|
||||
* @param $message
|
||||
* @param array $context
|
||||
*/
|
||||
public static function debug($message, array $context = [])
|
||||
{
|
||||
self::writeLog('DEBUG', $message);
|
||||
self::getLogger()->addDebug($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 信息
|
||||
* @param $message
|
||||
* @param array $context
|
||||
*/
|
||||
public static function info($message, array $context = [])
|
||||
{
|
||||
$message = self::prefix() . self::backtrace() . $message;
|
||||
self::writeLog('INFO', $message);
|
||||
self::getLogger()->addInfo($message, $context);
|
||||
self::callback(Logger::INFO, 'INFO', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 提醒
|
||||
* @param $message
|
||||
* @param array $context
|
||||
*/
|
||||
public static function notice($message, array $context = [])
|
||||
{
|
||||
$message = self::prefix() . self::backtrace() . $message;
|
||||
self::writeLog('NOTICE', $message);
|
||||
self::getLogger()->addNotice($message, $context);
|
||||
self::callback(Logger::NOTICE, 'NOTICE', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 警告
|
||||
* @param $message
|
||||
* @param array $context
|
||||
*/
|
||||
public static function warning($message, array $context = [])
|
||||
{
|
||||
$message = self::prefix() . self::backtrace() . $message;
|
||||
self::writeLog('WARNING', $message);
|
||||
self::getLogger()->addWarning($message, $context);
|
||||
self::callback(Logger::WARNING, 'WARNING', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 错误
|
||||
* @param $message
|
||||
* @param array $context
|
||||
*/
|
||||
public static function error($message, array $context = [])
|
||||
{
|
||||
$message = self::prefix() . self::backtrace() . $message;
|
||||
self::writeLog('ERROR', $message);
|
||||
self::getLogger()->addError($message, $context);
|
||||
self::callback(Logger::ERROR, 'ERROR', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @use 回调
|
||||
* @param $levelId
|
||||
* @param $level
|
||||
* @param $message
|
||||
*/
|
||||
public static function callback($levelId, $level, $message)
|
||||
{
|
||||
// $callback_level = Logger::ERROR ?? getConf('callback_level', 'log');
|
||||
$callback_level = getConf('callback_level', 'log') ?? Logger::ERROR;
|
||||
if ($levelId >= $callback_level) {
|
||||
$url = str_replace('{account}', self::prefix(), getConf('callback', 'log'));
|
||||
$url = str_replace('{level}', $level, $url);
|
||||
$url = str_replace('{message}', urlencode($message), $url);
|
||||
Curl::request('get', str_replace(' ', '%20', $url));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user