# inphp-doc
**Repository Path**: lulanyin/inphp-doc
## Basic Information
- **Project Name**: inphp-doc
- **Description**: INPHP服务框架文档
- **Primary Language**: HTML
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: https://inphp.cc
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-08-03
- **Last Updated**: 2023-09-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# INPHP
> 欢迎使用INPHP
- [开发框架](https://www.gitee.com/lulanyin/inphp-framework)
- [核心库](https://www.gitee.com/inphp-modules/core)
`此框架从未在windows系统中测试过,线上应用的系统环境均是linux`
扫码关注,技术交流!
## 支持服务
## 内置操作库
Db (支持连接池,PHP原生PDO对象,支持事务,内置语法目前仅适配Mysql)
## 环境说明
+ PHP >= 8.0
+ 使用了`swoole`拓展,支持CLI运行服务,开发时基于`swoole 5.0`,建议使用`swoole`拓展服务,以获得更好的PHP性能
+ 支持`PHP-FPM`方式运行,此方式不支持使用`swoole`拓展的相关的类、函数、变量、常量
## 框架文件结构
```
app ----------------------------------- 存放各个应用模块的文件夹
+-- admin ----------------------------- 后台模块
+-- install --------------------------- 安装引导模块
bin ----------------------------------- 启动目录
+-- bootstrap.php --------------------- 启动入口文件
+-- cmd ------------------------------- 各模块的自定义终端命令入口
+-- inphp ----------------------------- 服务启动入口
configs ------------------------------- 配置,所有配置都放在这里
+-- private --------------------------- 私有配置
+--+-- db.php ------------------------- pdo/redis配置
+--+-- smarty.php --------------------- Smarty模板引擎配置
+-- public ---------------------------- 所有模块的自定义配置文件存放目录(保存为JSON文件)
+-- define.php ------------------------ 系统运行起始的重要配置
+-- domain.php ------------------------ 域名配置,默认自动识别当前域名
+-- env.php --------------------------- 运行环境配置文件,目前仅用于 开发模式、生产环境的开关配置
+-- middlewares.php ------------------- 中间键配置
+-- modules.php ----------------------- 多模块配置
+-- server.php ------------------------ 服务配置
public -------------------------------- 站点暴露的公共文件夹,Nginx请绑定到此
+-- assets ---------------------------- 站内资源文件存放目录
+-- index.php ------------------------- PHP-FPM服务的站点入口文件
runtime ------------------------------- 运行时缓存、日志存放目录,请保证读写权限
```
## 常规安装
```bash
# 先进入站点文件夹
cd /www/webroot
# 克隆本项目到本地
git clone https://gitee.com/lulanyin/inphp-framework.git www.xxxx.com
# 进入项目文件夹
cd www.xxxx.com
# 安装依赖包
composer install
```
可访问 http://www.xxxx.com/install 进行基础配置,支持在根目录放置 `install.sql` 文件,可恢复。
## Nginx 站点配置
### 纯PHP-FPM站点
```nginx
server{
# 端口
listen 80;
# 域名
server_name www.xxxx.com;
# 站点目录
root /www/webroot/www.xxxx.com/public;
# 默认索引文件
index index.php;
# 伪静态
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php/$1 last;
break;
}
# 日志
access_log /www/nginx/logs/xxxx-access.log;
error_log /www/nginx/logs/xxxx-error.log;
# php处理
location ~ \.php {
# 路径参数
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
# 方式一
# fastcgi_pass 127.0.0.1:9000;
# 方式二 请注意自己系统的PHP版本,支持php8.0+
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 静态文件,为避免资源文件出现跨域请求错误
location ~ (.*)\.(html|js|map|css|jpg|png|jpeg|gif|bmp|ttf|ttc|otf|eot|woff|woff2|svg|ico)$ {
# 限定域名, * 为不限定
add_header Access-Control-Allow-Origin *;
# 限定 header
add_header Access-Control-Allow-Headers *;
# 静态资源,仅支持GET请求方式
add_header Access-Control-Allow-Methods GET;
# 如果文件不存在,直接 404
try_files $uri @s404;
}
#404
location @s404{
return 404;
}
}
```
### swoole 协程服务站点
```nginx
server{
# 端口
listen 80;
# 域名
server_name www.xxxx.com;
# 日志
access_log /www/nginx/logs/xxxx-access.log;
error_log /www/nginx/logs/xxxx-error.log;
# 静态文件,为避免资源文件出现跨域请求错误
location ~ (.*)\.(html|js|map|css|jpg|png|jpeg|gif|bmp|ttf|ttc|otf|eot|woff|woff2|svg|ico)$ {
# 静态资源请求目录
root /www/webroot/www.xxxx.com/public;
# 限定域名, * 为不限定
add_header Access-Control-Allow-Origin *;
# 限定 header
add_header Access-Control-Allow-Headers *;
# 静态资源,仅支持GET请求方式
add_header Access-Control-Allow-Methods GET;
# 如果文件不存在,直接 404
try_files $uri @s404;
}
#404
location @s404{
return 404;
}
# swoole
location / {
proxy_redirect off;
# 转发真实域名host
proxy_set_header Host $host;
# 转发真实IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 说明本站点使用的请求前段是 http 还是 https
proxy_set_header X-Request-Scheme http;
# 引用 upstream 的名称,区分http, https
proxy_pass http://127.0.0.1:1990;
proxy_connect_timeout 300s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffer_size 64k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_ignore_client_abort on;
# 支持websocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
## 站点服务启动
### 终端命令方式
#### HTTP
```bash
php /www/webroot/www.xxxx.com/bin/inphp http hotUpdate
```
#### HTTP + Websocket
```bash
php /www/webroot/www.xxxx.com/bin/inphp ws hotUpdate
```
> 第一个参数可使用 `http`或`ws`或`websocket`,表示要开启的服务端类型,第二个参数`hotUpdate` 表示开启热更新。`websocket`服务默认开启了`HTTP`的`onRequest`请求,不提供响应的控制器即可自动404。热更新可以在开发时开启,比较方便测试。
## 开发自定义模块
框架开发之初,结构设计上是在`app`文件夹里存放与项目相关逻辑代码,但随着长期的使用发现,经常会遇到相同功能逻辑的代码重复出现在不同的项目里,后来便想设计一种类似可将相同功能逻辑的代码独立打包,然后归纳到一个文件夹中,放置在`app`目录下,并且可以单独配置,便形成现在的独立模块(`module`)。
类似于一个`商城项目`,里边会出现:`新闻公告发布`、`文件上传管理`、`商品管理`、`订单管理`、`财务系统(收银、退款、流水...)` 等等功能,而这些功能,本身是可以出现在很多类型的项目里边。
根据这样的一个使用思路,框架便更新至现目前这样一个形态,系统可拆分为多个模块,各模块代码可以独立,常用的模块代码可实现真正的代码独立,与其它模块代码互不影响,也可以相互调用,未来也会保持使用这一个思路去进行升级和维护。
在此章节,我们将以开发一个`文件管理系统`模块为例子进行使用讲解,该模块命名索性使用 `fs` 吧,需要注意的是,因文件上传时的临时数据会保存到内存中(CLI模式),需要控制分片大小。
!> 往下再次出现的配置代码,将以简要说明为主,会标注出代码插入的位置,不再重复前面配置里的完整代码和注解。
### 创建模块目录
在 `app` 文件夹中,创建名称为 `fs` 的文件夹,一个基本的模块内部文件结构如下:
```
app ----------------------- 存放各个应用模块的文件夹,模块开发请存在在这之中
+-- fs -------------------- 新添加的文件管理系统模块
+--+-- assets ------------- 模板内部使用的样式、资源存放
+--+-- http --------------- http 控制器目录
+--+--+-- api ------------- api接口模块
+--+--+--+-- files.php ---- 文件管理接口
+--+--+--+-- upload.php --- 文件上传接口
+--+-- view --------------- 视图目录
+--+--+-- web ------------- 客户端视图目录
+--+--+--+-- index.html --- 客户端默认首页视图
+--+-- admin.php ---------- 后台菜单配置
+--+-- module.json -------- 模块配置
```
#### 后台菜单配置 admin.php
```php
return [
["name" => "文件管理", "icon" => "fa fa-file", "url" => "./web/index"]
];
```
#### 模块配置 module.json
```json
{
"id": "fs",
"name": "文件管理模块",
"icon": "fa fa-file",
"version": 20230911,
"appid": 202309001,
"detail": {
"authors": [
{"name": "幺月儿", "face": "", "url": "https://gitee.com/lulanyin"}
],
"url": "https://gitee.com/inphp-modules/fs"
},
"autoload": [],
"http": {
"root": "http",
"controller": {
"api": true,
"web": false
},
"modules": {
"api": "api",
"web": "web"
},
"defaultModule": "web",
"view": "view",
"response": {
"api": {
"contentType": "application/json",
"accessHeaders": "",
"accessMethods": ["GET", "OPTIONS", "POST"],
"accessOrigins": "*"
}
}
},
"require": {
"composer": [
{
"name": "intervention/image",
"version": "^2.7"
}
],
"modules": []
}
}
```
##### 参数说明
- 参数
- 说明
- 示例值
- id
- 对应命名空间名称、模块的文件夹名称,请勿与其它模块重复
- fs
- name
- 模块名称,默认的后台会截取前2个字作为菜单名称
- 文件管理
- icon
- 请使用 fontawesome.com 的图标样式名称
- fa fa-list
- version
- 版本号,仅支持纯数字,建议使用日期+序号方式
- 2023092700001
- appit
- 应用ID,可登陆 INPHP官方 注册获得
- 20230927001
- detail
-
应用详情,包含作者列表、应用官网链接
- 下级属性参数
- 说明
- 示例值
- authors
- 作者列表数组
- [{"name": "幺月儿", "face": "", "url": "https://gitee.com/lulanyin"}]
- url
- 应用官网链接
- https://gitee.com/inphp-modules/fs
- autoload
- 自动加载的文件,路径请使用相对应路径,支持多个
- ["function.php"]
- http
- HTTP服务配置
- 下级属性参数
- 说明
- 示例值
- root
- http根目录
- http
- controller
- 子模块的控制器开关,true:表示需要控制器,控制器不存在时,将404
- {"api":true, "web":false}
- modules
- 子模块配置,key值是地址入口,value对应命名空间
- {"api":"api","web":"web"}
- defaultModule
- 默认子模块
- web
- view
- 视图根目录
- view
- response
- 子模块响应的数据类型、请求限制等...
- 参考上方配置文件
- ws
- WS服务配置
- 参考HTTP配置
- require
- composer依赖、其它模块依赖配置
- 下级属性参数
- 说明
- 示例值
- composer
- composer依赖,支持多个
- [{"name": "intervention/image", "version": "^2.7"}]
- modules
- 模块依赖,支持多个
- [{"name":"xxxx","appid":2023090002,"version":20230900045}]
### 控制器
控制器必须是 `class` 对象,一个基础的控制器如下,用文件管理作为示例:
`控制器请求链接构成为:[域名]/[模块]/[子模块]/[类名|默认index]/[方法名|默认index]`
```php
whereIn("type", [$type, "dir"]);
}
//上级文件夹ID
$parentId = GET("parentId", 0);
$parentId = is_numeric($parentId) && $parentId > 0 ? ceil($parentId) : 0;
$db->where("parentId", $parentId);
//分组
$groupName = GET("groupName");
if (!empty($groupName) || $groupName == "0") {
$db->where("groupName", (string) $groupName);
}
//搜索
$keyword = GET("keyword");
$keyword = !empty($keyword) ? trim($keyword) : null;
if (!empty($keyword)) {
$db->whereLike("name", "%{$keyword}%");
}
//取全部
$list = $db->where("destroy", 0)->orderBy("weight", "asc")->orderBy("name", "asc")->get();
foreach ($list as &$item) {
$item["url"] = !empty($item["src"]) ? attachmentUrl($item["src"]) : null;
}
//直接返回列表数据即可,因模块配置 module.php 里边已指定 api 目录下的数据返回格式是JSON,会自动处理为 { "error":0, "message":"success", "data":[文件列表] }
return $list;
}
/**
* 删除文件
* @return Message
*/
public function delete(): Message
{
$idList = POST("id");
//处理
$idList = !empty($idList) ? explode(",", Str::trim($idList)) : [];
if (empty($idList)) {
return httpMessage("未指定文件的ID");
}
$id = [];
foreach ($idList as $val) {
if (is_numeric($val) && $val > 0 && !in_array($val, $id)) {
$id[] = $val;
}
}
if (empty($id)) {
return httpMessage("未指定文件的ID,数据无效!");
}
$db = Db::from("fs_files")
->whereIn("id", $id);
if ($db->update(["destroy" => 1])) {
return httpMessage(0, "作废了{$db->getAffectRows()}个文件");
}
return httpMessage("文件作废失败");
}
}
```
#### 使用注解
系统已经添加了处理PHP8注解的功能,注解默认在 [beforeExecute](?id=beforeExecute) 事件触发时处理。
```php
namespace app\fs\http\api;
use app\admin\attributes\auth;
//在 class 前,添加 #[注解类名]
//方式一,无需参数时:#[auth] 或 #[auth()]
//方式二,有参数时:#[auth(参数一, 参数二)]
//方式三,多个注解:#[attr1(arg1, arg2, ...), attr2, attr3, ... , attrN]
#[auth()] class files
{
public function list()
{
//code ...
}
}
```
#### 使用全局对象
系统默认了一些对象,如客户端对象 `\Inphp\Core\Object\Client`,`HTTP` 响应对象 `\Inphp\Core\Services\Http\Response`, 服务入口对象 `\Inphp\Core\Services\Http\Server` 等,如要使用这些对象,可参照下方代码:
```php
rawData;//或者:$client->get("rawData");
//赋值到Smarty模板引擎变量
viewAssign("name", $name);
viewAssign("version", $version);
//获取客户端IP
$ip = getIP();
//强制重定向
redirect("https://inphp.cc", 302);
}
}
```
#### 响应数据
如果未在 `{模块目录}/module.php` 下配置响应数据类型,默认响应数据格式为 `text/html`,是需要视图配合响应的,否则将会出现 `404` 状态。若设置了响应数据格式为 `application/json`,默认的数据格式为:`{"error":0,"mesage":"success","data":[]}`。
##### json
```php
0,
"page" => 1,
"pages" => 0,
"list" => []
]);
}
/**
* 如果已定义了响应的数据格式是 application/json
* 方法里边返回的是数组或非 \Inphp\Core\Object\Message 对象,所有数据都会赋值给 data,
* 方法返回的是 \Inphp\Core\Object\Message 对象,则以实际参数为准
*/
public function json(): array
{
//自动转化为:{"error":0,"mesage":"success","data":{"rows":0,"page":1,"pages":0","list":[]}} 输出给客户端
return [
"rows" => 0,
"page" => 1,
"pages" => 0,
"list" => []
];
}
}
```
##### 其它
```php
withBody($img, $response::CONTENT_TYPE_IMAGE_JPEG);
//如果需要直接输出
$response->end();
}
}
```