# MengPHP
**Repository Path**: myDcool/meng-php
## Basic Information
- **Project Name**: MengPHP
- **Description**: 模块化小型PHP框架
- **Primary Language**: PHP
- **License**: MulanPSL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 1
- **Created**: 2022-04-28
- **Last Updated**: 2025-02-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# MengPHP
- 模块化, 静态化, 层级少, 易调试, 支持多数据库链接/读写分离
- 参考文档: http://doc.hearu.top/ (最近服务器被攻击, 可以到 /tool/document/ 目录下查看文档)
- 如果不需要连接数据库或Redis可以不配置
## 一, 目录结构
```
MengPHP Framework
|-- core 框架的核心类
|-- config 配置文件
|-- libs 第三方库
|-- model 模型类, 理论上用于写获取数据的具体逻辑, 只放置在根目录下, 任何控制器都可以调用到
|-- tables 表结构信息, 自动从数据库读取表结构信息生成的类文件, 方便SQL组装和了解表结构
|-- router 路由规则文件
|-- modules 项目模块
|-- view 视图文件
|-- tool 框架自带的登录注册模块的SQL,数据库配置文件样例,windows启动php-cgi的脚本
|-- update 框架自更新脚本
|-- static 静态文件存放
|-- cli.php 命令行下的入口文件 php cli.php -q m_c_a
`-- index.php 入口文件
```
## 二, 安装步骤
### 1. 下载框架代码到
> E:/php/code/project
### 2. 配置NGINX
```
# 精简版 (没有限速和安全配置)
http {
...
server {
listen 80;
server_name www.test.com;
location ~ \.(ico|jpg|gif|png|js|css)$ {
root E:/php/code/project/static;
#expires 1h;
}
location / {
root E:/php/code/project;
# fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
}
}
```
```
# 增加限速和安全配置
http {
...
# 限速全局配置, 详细用法可去nginx官网查询 (https://nginx.org/en/docs/ -> ngx_http_limit_req_module ngx_http_limit_conn_module)
limit_rate 100k; # 每个链接限制 100k 字节
limit_req_zone $binary_remote_addr zone=perip:5m rate=1r/s; # 单IP请求限制, 每秒1个, 5M的记录空间, 空间名为perip, 下边会用到
limit_req_zone $server_name zone=perserver:5m rate=50r/s; # 单个server响应限制, 5M的记录空间, 空间名为perserver, 下边会用到
...
server {
listen 80;
server_name www.test.com;
#限速配置 (也可以写在location中)
limit_req zone=perip burst=5 nodelay; # 使用名为perip的限速设置, 超出的不再处理直接返回503
limit_req zone=perserver burst=10; # 使用名为perserver的限速设置, 超出的排队等待处理
#安全配置开始
if ($request_method !~ ^(GET|POST)$) {return 405;}
location ~ x0 {return 404;} # 8进制/16进制数据限制
location ~ ^/\..*{return 404;} # 以.开始的访问限制(比如 .evn .git)
location ~ \./.* {return 404;} # 路径访问限制 (比如: /../../abc.xxx)
location ~* ^/http {return 404;}
location ~* \.(php|asa|asp|aspx|html|git|sh|exe|xml|json)$ {return 404;} # 后缀限制
#安全配置结束
location ~ \.(ico|jpg|gif|png|js|css)$ {
root E:/php/code/project/static;
#expires 1h;
}
location / {
root E:/php/code/project;
# fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_pass 127.0.0.1:9720;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
}
}
```
### 3. 修改hosts文件,添加解析:`127.0.0.1 www.test.com`
### 4. 启动nginx;
### 5. 安装,启动php
- windows:
- 安装: 从官网下载最新的php代码, 解压到某个目录
- 启动: 参考`tool/script/` 目录下的启动脚本
- Linux
- 安装 & 启动 & 开启自启: 使用remi源进行安装, 参考: https://www.cnblogs.com/iLoveMyD/p/17127099.html
### 6. 在浏览器中输入 www.test.com 访问首页
## 三, 核心功能使用说明
### URL路由
> 核心代码参考 core/Route.php::matchURI();
#### 1. 配置路由规则
- 所有对外可访问的接口都要在 router/*.php 中配置映射规则, 接口与真正的方法是映射关系, 不直接暴露源代码的方法名
- 路由规则分散在多个文件中, 防止多人协作开发时代码冲突
#### 2. 配置举例
```
//router/test.php http://www.test.com/test/detail_123
$GLOBALS['router']['test'] = [
'article_list_(\d+)' => 'article/home/get_list/page/$1',
'detail_(\d{3})' => 'article/index/detail/id/$1',
];
//router/user.php http://www.test.com/user/login
$GLOBALS['router']['user'] = [
//用户账号相关
'default' => 'user/login', //都不匹配时走这个'default'路由
'user' => 'user/index',
'login' => 'user/login/index',
'register' => 'user/register/index',
'logout' => 'user/logout/index',
];
```
#### 在命令行中使用路由
```
php cli.php -q cli/db_class //指定去匹配router/cli.php中的路由
```
### 获取请求数据
> 参考 core/Request.php
#### 1. 获取一个值
```
Request::Get('a', 'default');
Request::Post('a');
Request::Cookie('a');
Request::Route('a');
Request::Json('a'); //前端以json形式上传的数据(content-type: application/json)
```
#### 2. 按类型获取
```
Request::Get()::Number('age', 11);
Request::Post()::Int('age', 11);
Request::Cookie()::Float('age', 1.11);
Request::Server()::String('name', 'zs');
```
#### 3. 一次获取多个值, 没有则用默认值替代
```
Request::Post()::pickData(['a' => 0, 'b' => '', 'c' => '0']);
```
### 返回结果
> 参考 core/Response.php
#### 1. 输出固定格式的json数据
```
$a = ['list' => [1,2,3,4]];
Response::json(10000, '用户列表', $a);
结果: {"code":10000,"msg":"\u7528\u6237\u5217\u8868","data":{"list":[1,2,3,4]}}
```
#### 2. 便捷调用
> Response::json()的简写, 返回结构是一样的
##### 成功返回
```
Response::success($a);
Response::success($a, '用户列表');
Response::success($a, '用户列表', 20000);
```
##### 失败返回
```
Response::error('参数错误'); // 结果: {"code":"-1","msg":"\u53c2\u6570\u9519\u8bef","data":[]]}
Response::error('参数错误', $a); // 结果: {"code":"-1","msg":"\u53c2\u6570\u9519\u8bef","data":{"list":[1,2,3,4]},"url":""}
Response::error('参数错误', $a, 20001); //结果: {"code":2001,"msg":"\u53c2\u6570\u9519\u8bef","data":{"list":[1,2,3,4]}}
```
#### 3. 返回任意结构的json数据
```
Response::jsonReturn($a); //{"list":[1,2,3,4]}
```
#### 4. 跳转
```
Response::notify('页面找不到啦~'); //页面找不到啦~
Response::redirect('充值成功, 页面即将跳转', 'http://www.hearu.top', 3);
Response::jump('http://www.hearu.top'); //直接跳转
```
### 返回HTML页面
> 参考: core/View.php
#### 1. 显示单个页面
```
View::display();
```
#### 2. 插入式显示页面(一个HTML页面框架, 里边有占位符:{{xxx}})
```
View::render();
```
### 数据库
> 更多增删改查操作请查看在线文档
#### 数据库链接账号密码配置
```
入口文件 index.php 中有个define配置:
define('MYSQL_HOST_FILE', '/var/www/dbConfig.json'); //存放mysql主机信息的json文件地址, 参考 tool/dbConfig.json
修改这个配置的值为dbConfig.json的实际位置即可
```
#### 相关操作摘要
```
use Tables\DefaultUser as User;
//增
$insertId = User::user()
->insert(['username' => '王五', 'age' => 18])
->insertId;
//删
$affectRows = User::user()
->where(['uid' => 5])
->delete()
->affectRows;
//改
$affectRows = User::user()
->where(['uid' => 1])
->updateVal(['age' => 20])
->updateOp('a', 'a', '+', 1)
->updateOp('a', 'b', '+', 2)
->update()
->affectRows;
//查
$rs = User::user()
->where(['status' => 0, 'deleted' => 0])
->whereOp('uid', '<', 10)
->order('uid desc')
->selectAll();
//join
$tbUser = User::$user;
$tbUserRole = User::$role_bind;
$tbRole = User::$role;
$rs = User::user()
->joinFields($tbUser, 'uid,username')
->joinFields($tbRole, 'name,access')
->joinTable([$tbUser, 'uid'],[$tbUserRole, 'uid'])
->joinTable([$tbUserRole, 'roleid'], [$tbRole, 'id'])
->where(['status' => 0, 'is_logout' => 0], $tbUser)
->where(['status' => 0], $tbUserRole)
->where(['status' => 0], $tbRole)
->joinAll();
Response::success($rs, DB::$currentSql);
```
### 文件日志
> 参考 libs/FileLog.php
> 日志文件存放的目录在入口文件 index.php 和 cli.php 中配置: `LOGPATH`
#### 1. 常用
```
FileLog::info([msg], 'tag'); //日志文件: LOGPATH/info/yyyy-mm-dd.log, 数组内容会被转为json, 字符串会原样输出
或
FileLog::error('哈哈哈哈');
```
#### 2. 设置日志跟踪ID
```
FileLog::$trace_id = time().Fun::randChar(5); //默认为 uniqid() 或 $_GET['trace_id'] 的值
```
### Redis消息队列
- 基础类在: libs/IRedis.php
- 队列类在: model/RedisQueue.php
- 队列名的配置在: config/topics.php
- 具体实现参考: modules/cli/queue.php
### DB消息队列
- 队列类在: model/DBQueue.php
- Topic的配置在: config/topics.php
- 需要添加消费者的crontab (路由: cli_queue_db_consumer), 代码在 module/cli/queue_db.php
### 自带登录注册模块
- 用户信息用cookie加密存储
- 功能有: 登录/注册/退出, 其中注册提供图形验证码
### 自带前端单页面应用(SPA)样例
- 按照上边说明安装好PHP运行环境
- 配置好数据库信息(dbConfig.json)
- 浏览器访问首页,即是一个可查看个多主机/数据库/表/字段等信息的web应用
## 四, 安全建议
### 代码级别
- 尽量用post: 绝大部分的xss攻击是通过