Skip to content

Commit 1905152

Browse files
authored
Merge pull request #40 from xudianyang/master
+ HTTP静态文件的支持
2 parents b029071 + dc4a5ca commit 1905152

13 files changed

Lines changed: 215 additions & 73 deletions

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ PHP微服务框架即“Micro Service Framework For PHP”,是[Camera360](http
2020
* IO密集性业务的单机处理能力提升5-10倍
2121
* 代码常驻内存
2222
* 支持对象池
23-
* 支持Redis连接池、MySQL连接池
24-
* 支持Redis Proxy分布式、master-slave部署结构的集群
25-
* 支持MySQL Proxy master-slave部署结构的集群(读写分离、事务)
23+
* 支持Redis连接池、MySQL连接池(异步与同步)
24+
* 内置Redis Proxy,支持分布式、master-slave集群(故障自动failover与recovery)
25+
* 内置MySQL Proxymaster-slave集群(读写分离、事务)
2626
* 支持异步、并行
2727
* 基于PHP Yield实现协程
2828
* 内建http/redis/mysql/mongodb/task等协程客户端
@@ -31,6 +31,7 @@ PHP微服务框架即“Micro Service Framework For PHP”,是[Camera360](http
3131
* 支持命令行模式
3232
* 支持独立进程的定时器
3333
* 支持独立配置进程
34+
* 支持sendfile静态文件(需配置root目录)
3435

3536
## 环境要求
3637

src/Base/Core.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PG\MSF\Proxy\RedisProxyFactory;
1818
use PG\MSF\Proxy\MysqlProxyFactory;
1919
use PG\MSF\Pools\CoroutineRedisProxy;
20+
use PG\MSF\Proxy\MysqlProxyMasterSlave;
2021

2122
/**
2223
* Class Core
@@ -203,8 +204,8 @@ public function getMysqlPool(string $poolName)
203204
/**
204205
* 获取Mysql代理
205206
*
206-
* @param string $proxyName 配置的Redis代理名称
207-
* @return bool|Wrapper|CoroutineRedisProxy|\Redis
207+
* @param string $proxyName 配置的MySQL代理名称
208+
* @return Wrapper|mysqlProxyMasterSlave|Miner|MysqlAsynPool
208209
* @throws Exception
209210
*/
210211
public function getMysqlProxy(string $proxyName)

src/Base/Input.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Input extends Core
3131
*/
3232
public function __sleep()
3333
{
34-
$this->__serializeRequest = new \swoole_http_request();
34+
$this->__serializeRequest = new \stdClass();
3535
$this->__serializeRequest->get = $this->request->get ?? [];
3636
$this->__serializeRequest->post = $this->request->post ?? [];
3737
$this->__serializeRequest->files = $this->request->files ?? [];

src/HttpServer.php

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public function onRequest($request, $response)
145145
// 构造请求日志对象
146146
$PGLog = clone getInstance()->log;
147147
$PGLog->accessRecord['beginTime'] = microtime(true);
148-
$PGLog->accessRecord['uri'] = $this->route->getPath();
148+
$PGLog->accessRecord['uri'] = $this->route->getPath() ?: '/';
149149
$PGLog->logId = $logId;
150150
defined('SYSTEM_NAME') && $PGLog->channel = SYSTEM_NAME;
151151
$PGLog->init();
@@ -155,9 +155,20 @@ public function onRequest($request, $response)
155155

156156
do {
157157
if ($this->route->getPath() == '') {
158-
$error = 'Index not found';
159-
$httpCode = 404;
160-
break;
158+
$indexFile = $this->config['http']['domain'][$this->route->getHost()]['index'] ?? __DIR__ . '/Views/index.html';
159+
$response->header('X-Ngx-LogId', $PGLog->logId);
160+
$httpCode = $this->sendFile($indexFile, $request, $response);
161+
$PGLog->pushLog('http-code', $httpCode);
162+
$PGLog->appendNoticeLog();
163+
return;
164+
}
165+
166+
if ($this->route->getFile()) {
167+
$response->header('X-Ngx-LogId', $PGLog->logId);
168+
$httpCode = $this->sendFile($this->route->getFile(), $request, $response);
169+
$PGLog->pushLog('http-code', $httpCode);
170+
$PGLog->appendNoticeLog();
171+
return;
161172
}
162173

163174
$controllerName = $this->route->getControllerName();
@@ -340,4 +351,60 @@ public function genLogId($request)
340351

341352
return $logId;
342353
}
354+
355+
/**
356+
* 直接响应静态文件
357+
*
358+
* @param string $path
359+
* @param \swoole_http_request $request 请求对象
360+
* @param \swoole_http_response $response 响应对象
361+
* @return int
362+
*/
363+
public function sendFile($path, $request, $response)
364+
{
365+
$path = realpath(urldecode($path));
366+
$root = $this->config['http']['domain'][$this->route->getHost()]['root'] ?? null;
367+
368+
// 判断文件是否存在
369+
if (!file_exists($path)) {
370+
$response->status(404);
371+
$response->end('');
372+
return Marco::SEND_FILE_404;
373+
}
374+
375+
// 判断文件是否有权限(非root目录不能访问)
376+
if (empty($root) || strpos($path, $root) === false) {
377+
$response->status(403);
378+
$response->end('');
379+
return Marco::SEND_FILE_403;
380+
}
381+
382+
$info = pathinfo($path);
383+
$extension = strtolower($info['extension'] ?? '');
384+
385+
// 判断缓存
386+
$lastModified = gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT';
387+
if (isset($request->header['if-modified-since']) && $request->header['if-modified-since'] == $lastModified) {
388+
$response->status(304);
389+
$response->end('');
390+
return Marco::SEND_FILE_304;
391+
}
392+
393+
$normalHeaders = getInstance()->config->get("fileHeader.normal", ['Content-Type: application/octet-stream']);
394+
$headers = getInstance()->config->get("fileHeader.$extension", $normalHeaders);
395+
396+
foreach ($headers as $value) {
397+
list($hk, $hv) = explode(': ', $value);
398+
$response->header($hk, $hv);
399+
}
400+
401+
$response->header('Last-Modified', $lastModified);
402+
if (!$response->sendfile($path)) {
403+
swoole_async_readfile($path, function ($filename, $content) use ($response) {
404+
$response->end($content);
405+
});
406+
}
407+
408+
return Marco::SEND_FILE_200;
409+
}
343410
}

src/Marco.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,24 @@ class Marco
9898
* 进程为user
9999
*/
100100
const PROCESS_USER = 3;
101+
102+
/**
103+
* 发送静态文件404
104+
*/
105+
const SEND_FILE_404 = 404;
106+
107+
/**
108+
* 发送静态文件200
109+
*/
110+
const SEND_FILE_200 = 200;
111+
112+
/**
113+
* 发送静态文件304
114+
*/
115+
const SEND_FILE_304 = 304;
116+
117+
/**
118+
* 发送静态文件403
119+
*/
120+
const SEND_FILE_403 = 403;
101121
}

src/Pools/Miner.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,22 +1871,26 @@ public function go($bindId = null, $sql = null)
18711871
$sql = $this->getStatement(false);
18721872
}
18731873
if (getInstance()->isTaskWorker()) {//如果是task进程自动转换为同步模式
1874-
$this->mergeInto($this->mysqlPool->getSync());
1874+
$profileName = $this->mysqlPool->getAsynName() . '(' . str_replace("\n", " ", $sql) . ')';
1875+
$this->getContext()->getLog()->profileStart($profileName);
1876+
1877+
$this->mergeInto($this->mysqlPool->getSync($this->getContext()));
18751878
$this->clear();
18761879
$data = array();
18771880
switch ($sql) {
18781881
case 'commit':
1879-
$this->mysqlPool->getSync()->pdoCommitTrans();
1882+
$this->mysqlPool->getSync($this->getContext())->pdoCommitTrans();
18801883
break;
18811884
case 'begin':
1882-
$this->mysqlPool->getSync()->pdoBeginTrans();
1885+
$this->mysqlPool->getSync($this->getContext())->pdoBeginTrans();
18831886
break;
18841887
case 'rollback':
1885-
$this->mysqlPool->getSync()->pdoRollBackTrans();
1888+
$this->mysqlPool->getSync($this->getContext())->pdoRollBackTrans();
18861889
break;
18871890
default:
1888-
$data = $this->mysqlPool->getSync()->pdoQuery($sql);
1891+
$data = $this->mysqlPool->getSync($this->getContext())->pdoQuery($sql);
18891892
}
1893+
$this->getContext()->getLog()->profileEnd($profileName);
18901894
return $data;
18911895
} else {
18921896
$this->clear();
@@ -2549,12 +2553,14 @@ protected function pdoExecute($sql, $palceholderValues)
25492553
// Only execute if a statement is set.
25502554
if ($statement) {
25512555
try {
2552-
$PdoStatement = $PdoConnection->prepare($statement);
2556+
$PdoStatement = @$PdoConnection->prepare($statement);
25532557
if (empty($palceholderValues)) {
25542558
$palceholderValues = $this->getPlaceholderValues();
25552559
}
25562560
$PdoStatement->execute($palceholderValues);
25572561
} catch (\PDOException $e) {
2562+
$logWarn = dump($e, false, true) . $this->mysqlPool->getAsynName() . ' reconnect';
2563+
$this->getContext()->getLog()->warning($logWarn);
25582564
// 服务端断开时重连一次
25592565
if ($e->errorInfo[1] == 2006 || $e->errorInfo[1] == 2013) {
25602566
$this->setPdoConnection(null);
@@ -2580,7 +2586,9 @@ protected function pdoExecute($sql, $palceholderValues)
25802586

25812587
/**
25822588
* PDO连接
2583-
* @param $activeConfig
2589+
*
2590+
* @param array $activeConfig
2591+
* @return $this
25842592
*/
25852593
public function pdoConnect($activeConfig)
25862594
{
@@ -2596,6 +2604,8 @@ public function pdoConnect($activeConfig)
25962604
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
25972605
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
25982606
$this->setPdoConnection($pdo);
2607+
2608+
return $this;
25992609
}
26002610

26012611
/**

src/Pools/MysqlAsynPool.php

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ class MysqlAsynPool extends AsynPool
4848
*/
4949
private $active;
5050

51-
/**
52-
* @var Miner 同步MySQL客户端
53-
*/
54-
private $mysqlClient;
55-
5651
/**
5752
* MysqlAsynPool constructor.
5853
*
@@ -75,11 +70,7 @@ public function __construct($config, $active)
7570
public function __call($name, $arguments)
7671
{
7772
$context = array_pop($arguments);
78-
if ($this->dbQueryBuilder == null) {
79-
$this->getDBQueryBuilder($context);
80-
}
81-
82-
return $this->dbQueryBuilder->{$name}(...$arguments);
73+
return $this->getDBQueryBuilder($context)->{$name}(...$arguments);
8374
}
8475

8576
/**
@@ -260,17 +251,16 @@ public function getAsynName()
260251
}
261252

262253
/**
263-
* 开启一个事务
254+
* 开启一个同步事务
264255
*
265-
* @param callable $callback 执行完成后的回调函数
266256
* @param Context $context 请求上下文对象
267-
* @return string
257+
* @return $this
268258
*/
269-
public function begin($callback, Context $context = null)
259+
public function begin(Context $context = null)
270260
{
271-
$id = $this->bind($context);
272-
$this->query($callback, $id, 'begin', $context);
273-
return $id;
261+
$this->getDBQueryBuilder($context)->go(null, 'begin');
262+
263+
return $this;
274264
}
275265

276266
/**
@@ -324,25 +314,22 @@ public function query($callback, $bindId = null, $sql = null, Context $context =
324314
* @param Context $context 请求上下文对象
325315
* @return MySql
326316
*/
327-
public function coroutineBegin(Context $context = null)
317+
public function goBegin(Context $context = null)
328318
{
329-
if ($this->dbQueryBuilder == null) {
330-
$this->getDBQueryBuilder($context);
331-
}
332319
$id = $this->bind($context);
333-
return $this->dbQueryBuilder->go($id, 'begin');
320+
return $this->getDBQueryBuilder($context)->go($id, 'begin');
334321
}
335322

336323
/**
337-
* 提交一个事务
324+
* 提交一个同步事务
338325
*
339326
* @param Context $context 请求上下文对象
340-
* @param string $callback 执行完成后的回调函数
341-
* @param int $id 绑定ID
327+
* @return $this
342328
*/
343-
public function commit($callback, $id, Context $context = null)
329+
public function commit(Context $context = null)
344330
{
345-
$this->query($callback, $id, 'commit', $context);
331+
$this->getDBQueryBuilder($context)->go(null, 'commit');
332+
return $this;
346333
}
347334

348335
/**
@@ -352,24 +339,21 @@ public function commit($callback, $id, Context $context = null)
352339
* @param int $id 绑定ID
353340
* @return MySql
354341
*/
355-
public function coroutineCommit($id, Context $context = null)
342+
public function goCommit($id, Context $context = null)
356343
{
357-
if ($this->dbQueryBuilder == null) {
358-
$this->getDBQueryBuilder($context);
359-
}
360-
return $this->dbQueryBuilder->go($id, 'commit');
344+
return $this->getDBQueryBuilder($context)->go($id, 'commit');
361345
}
362346

363347
/**
364348
* 回滚
365349
*
366350
* @param Context $context 请求上下文对象
367-
* @param callable $callback 执行完成后的回调函数
368-
* @param int $id 绑定ID
351+
* @return $this
369352
*/
370-
public function rollback($callback, $id, Context $context = null)
353+
public function rollback(Context $context = null)
371354
{
372-
$this->query($callback, $id, 'rollback', $context);
355+
$this->getDBQueryBuilder($context)->go(null, 'rollback');
356+
return $this;
373357
}
374358

375359
/**
@@ -379,26 +363,25 @@ public function rollback($callback, $id, Context $context = null)
379363
* @param int $id 绑定ID
380364
* @return MySql
381365
*/
382-
public function coroutineRollback($id, Context $context = null)
366+
public function goRollback($id, Context $context = null)
383367
{
384-
if ($this->dbQueryBuilder == null) {
385-
$this->getDBQueryBuilder($context);
386-
}
387-
return $this->dbQueryBuilder->go($id, 'rollback');
368+
return $this->getDBQueryBuilder($context)->go($id, 'rollback');
388369
}
389370

390371
/**
391372
* 获取同步
373+
*
374+
* @param Context $context 请求上下文对象
392375
* @return Miner
393376
*/
394-
public function getSync()
377+
public function getSync(Context $context = null)
395378
{
396-
if (isset($this->mysqlClient)) {
397-
return $this->mysqlClient;
398-
}
399379
$activeConfig = $this->config['mysql'][$this->active];
400-
$this->mysqlClient = new Miner();
401-
$this->mysqlClient->pdoConnect($activeConfig);
402-
return $this->mysqlClient;
380+
$client = $this->getDBQueryBuilder($context);
381+
if ($client->getPdoConnection() === null) {
382+
return $client->pdoConnect($activeConfig);
383+
} else {
384+
return $client;
385+
}
403386
}
404387
}

src/Proxy/MysqlProxyFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static function makeProxy(string $name, array $config)
2727
{
2828
$mode = $config['mode'];
2929
if ($mode == Marco::MASTER_SLAVE) {
30-
return new mysqlProxyMasterSlave($name, $config);
30+
return new MysqlProxyMasterSlave($name, $config);
3131
} else {
3232
return false;
3333
}

0 commit comments

Comments
 (0)