[fix] Curl

This commit is contained in:
Lkeme 2020-02-24 13:00:14 +08:00
parent 90c5479a15
commit 5fdd14a9b3
15 changed files with 311 additions and 174 deletions

View File

@ -1,6 +1,25 @@
# Release Notes
# 本项目Log
## v0.2.0.200224 alpha (2020-02-24)
### Added
- 新增工具类
- 引入新库(需要重新Composer)
-
### Changed
- 优化数据过滤条件
- 更新PC端心跳API
- 优化实物抽奖
- 优化运行条件
-
### Fixed
- 修复内存异常
- 修复重复投币
-
## v0.2.0.200214 alpha (2020-02-14)
### Added

48
DOC.md
View File

@ -2,7 +2,7 @@
<p align="center"><img width="300px" src="https://i.loli.net/2018/04/20/5ad97bd395912.jpeg"></p>
<p align="center">
<img src="https://img.shields.io/badge/version-0.2.0.200214 alpha-green.svg?longCache=true&style=for-the-badge">
<img src="https://img.shields.io/badge/version-0.2.0.200224 alpha-green.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>
@ -15,29 +15,29 @@ B 站直播实用脚本
|plugin |version |description |
|--------------------|--------------------|--------------------|
|Login |20.02.14 |账号登录 |
|Sleep |20.02.14 |休眠控制 |
|MasterSite |20.02.14 |主站助手 |
|Daily |20.02.14 |每日礼包 |
|Heart |20.02.14 |双端心跳 |
|Task |20.02.14 |每日任务 |
|Silver |20.02.14 |银瓜子宝箱 |
|Barrage |20.02.14 |活跃弹幕 |
|Silver2Coin |20.02.14 |银瓜子换硬币 |
|GiftSend |20.02.14 |礼物赠送 |
|GroupSignIn |20.02.14 |友爱社签到 |
|ManGa |20.02.14 |漫画签到分享 |
|GiftHeart |20.02.14 |心跳礼物 |
|MaterialObject |20.02.14 |实物抽奖 |
|AloneTcpClient |20.02.14 |独立监控 |
|ZoneTcpClient |20.02.14 |分区监控 |
|StormRaffle |20.02.14 |节奏风暴 |
|GiftRaffle |20.02.14 |活动礼物 |
|PkRaffle |20.02.14 |大乱斗 |
|GuardRaffle |20.02.14 |舰长总督 |
|AnchorRaffle |20.02.14 |天选时刻 |
|AwardRecord |20.02.14 |获奖通知 |
|Statistics |20.02.14 |数据统计 |
|Login |20.02.24 |账号登录 |
|Sleep |20.02.24 |休眠控制 |
|MasterSite |20.02.24 |主站助手 |
|Daily |20.02.24 |每日礼包 |
|Heart |20.02.24 |双端心跳 |
|Task |20.02.24 |每日任务 |
|Silver |20.02.24 |银瓜子宝箱 |
|Barrage |20.02.24 |活跃弹幕 |
|Silver2Coin |20.02.24 |银瓜子换硬币 |
|GiftSend |20.02.24 |礼物赠送 |
|GroupSignIn |20.02.24 |友爱社签到 |
|ManGa |20.02.24 |漫画签到分享 |
|GiftHeart |20.02.24 |心跳礼物 |
|MaterialObject |20.02.24 |实物抽奖 |
|AloneTcpClient |20.02.24 |独立监控 |
|ZoneTcpClient |20.02.24 |分区监控 |
|StormRaffle |20.02.24 |节奏风暴 |
|GiftRaffle |20.02.24 |活动礼物 |
|PkRaffle |20.02.24 |大乱斗 |
|GuardRaffle |20.02.24 |舰长总督 |
|AnchorRaffle |20.02.24 |天选时刻 |
|AwardRecord |20.02.24 |获奖通知 |
|Statistics |20.02.24 |数据统计 |
## 打赏赞助

View File

@ -7,7 +7,7 @@ Group: [55308141](https://jq.qq.com/?_wv=1027&k=5AIDaJg)
## 公告
Currently for Personal Edition **0.2.0.200214 alpha**
Currently for Personal Edition **0.2.0.200224 alpha**
## 文档

View File

@ -15,7 +15,7 @@
"clue/socket-raw": "^1.4.1",
"vlucas/phpdotenv": "^4.1",
"amphp/amp": "^2.4",
"lkeme/curl-future": "^0.0.1"
"ares333/php-curl": "^4.6"
},
"license": "MIT",
"authors": [
@ -29,7 +29,8 @@
"psr-4": {
"BiliHelper\\Core\\": "src/core",
"BiliHelper\\Plugin\\": "src/plugin",
"BiliHelper\\Util\\": "src/util"
"BiliHelper\\Util\\": "src/util",
"BiliHelper\\Tool\\": "src/tool"
}
}
}

112
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "94b2a09fe75ecf7401a6694e164b252c",
"content-hash": "687175b9d9d6f818c02bd5174b036b19",
"packages": [
{
"name": "amphp/amp",
"version": "v2.4.0",
"version": "v2.4.1",
"source": {
"type": "git",
"url": "https://github.com/amphp/amp.git",
"reference": "13930a582947831bb66ff1aeac28672fd91c38ea"
"reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/amp/zipball/13930a582947831bb66ff1aeac28672fd91c38ea",
"reference": "13930a582947831bb66ff1aeac28672fd91c38ea",
"url": "https://api.github.com/repos/amphp/amp/zipball/2ac3b550c4997f2ec304faa63c8b2885079a2dc4",
"reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4",
"shasum": "",
"mirrors": [
{
@ -87,7 +87,56 @@
"non-blocking",
"promise"
],
"time": "2019-11-11T19:32:05+00:00"
"time": "2020-02-10T18:10:57+00:00"
},
{
"name": "ares333/php-curl",
"version": "v4.6.1",
"source": {
"type": "git",
"url": "https://github.com/ares333/php-curl.git",
"reference": "580025300c3cbf7cafe825bd454018ffc62233cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ares333/php-curl/zipball/580025300c3cbf7cafe825bd454018ffc62233cf",
"reference": "580025300c3cbf7cafe825bd454018ffc62233cf",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-curl": "*",
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Ares333\\Curl\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Ares",
"homepage": "http://phpdr.net"
}
],
"description": "The best php curl library.",
"keywords": [
"PHP cURL",
"aysnc http",
"curl",
"curlmulti"
],
"time": "2018-12-13T03:47:27+00:00"
},
{
"name": "bramus/ansi-php",
@ -244,45 +293,6 @@
],
"time": "2019-10-28T12:32:07+00:00"
},
{
"name": "lkeme/curl-future",
"version": "v0.0.1",
"source": {
"type": "git",
"url": "https://github.com/lkeme/CurlFuture.git",
"reference": "ea91acf250d2519cbd187d91fa6d01e9cfa9c6c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lkeme/CurlFuture/zipball/ea91acf250d2519cbd187d91fa6d01e9cfa9c6c5",
"reference": "ea91acf250d2519cbd187d91fa6d01e9cfa9c6c5",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"type": "library",
"autoload": {
"psr-4": {
"CurlFuture\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "leo",
"email": "263068280@qq.com"
}
],
"description": "Parallel CURL Requests with PHP --Fork",
"time": "2020-01-04T14:29:53+00:00"
},
{
"name": "monolog/monolog",
"version": "1.25.3",
@ -483,16 +493,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.13.1",
"version": "v1.14.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
"reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
"reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
"shasum": "",
"mirrors": [
{
@ -510,7 +520,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.13-dev"
"dev-master": "1.14-dev"
}
},
"autoload": {
@ -543,7 +553,7 @@
"polyfill",
"portable"
],
"time": "2019-11-27T13:56:44+00:00"
"time": "2020-01-13T11:15:53+00:00"
},
{
"name": "vlucas/phpdotenv",

View File

@ -24,6 +24,9 @@ class App
set_time_limit(0);
header("Content-Type:text/html; charset=utf-8");
date_default_timezone_set('Asia/Shanghai');
if (PHP_SAPI != 'cli') {
die("Please run this script from command line");
}
}
/**

View File

@ -10,8 +10,6 @@
namespace BiliHelper\Core;
use CurlFuture\HttpFuture;
class Curl
{
public static $headers = array(
@ -21,9 +19,40 @@ class Curl
'Connection' => 'keep-alive',
'Content-Type' => 'application/x-www-form-urlencoded',
'User-Agent' => 'bili-universal/8470 CFNetwork/978.0.7 Darwin/18.5.0',
// 'Referer' => 'https://live.bilibili.com/',
// 'Referer' => 'https://live.bilibili.com/',
);
private static $results = [];
private static $result = [];
/**
* @use 数组
* @return array
*/
private static function getResults()
{
$results = self::$results;
self::$results = [];
return $results;
}
/**
* @use 字符串or其他
* @return array
*/
private static function getResult()
{
$result = self::$result;
self::$result = [];
return array_shift($result);
}
/**
* @use 获取Headers
* @param $headers
* @return array
*/
private static function getHeaders($headers)
{
return array_map(function ($k, $v) {
@ -31,53 +60,110 @@ class Curl
}, array_keys($headers), $headers);
}
public static function asyncPost($url, $tasks = null, $headers = null, $timeout = 30)
/**
* @use 初始化Curl
* @param int $tasks_num
* @param bool $bar
* @return \Ares333\Curl\Curl
*/
private static function getMultiClient(int $tasks_num = 1, bool $bar = false)
{
$new_tasks = [];
$results = [];
$url = self::http2https($url);
$curl_options = [
$toolkit = new \Ares333\Curl\Toolkit();
$toolkit->setCurl();
$curl = $toolkit->getCurl();
$curl->maxThread = $tasks_num < 10 ? $tasks_num : 10;
if (!$bar) {
$curl->onInfo = null;
}
return $curl;
}
/**
* @use 填充CURL_OPT
* @param $url
* @param $payload
* @param $headers
* @param $timeout
* @return array
*/
private static function fillCurlOpts($url, $payload, $headers, $timeout): array
{
$default_opts = [
CURLOPT_URL => self::http2https($url),
CURLOPT_HEADER => 0,
CURLOPT_ENCODING => 'gzip',
CURLOPT_IPRESOLVE => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 0,
CURLINFO_HEADER_OUT => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_USERAGENT => self::$headers['User-Agent'],
CURLOPT_HTTPHEADER => is_null($headers) ? self::getHeaders(self::$headers) : self::getHeaders($headers),
CURLOPT_COOKIE => getenv('COOKIE') != "" ? getenv('COOKIE') : "",
// CURLOPT_CONNECTTIMEOUT => 10,
// CURLOPT_AUTOREFERER => true,
// CURLOPT_RETURNTRANSFER => true,
// CURLOPT_FOLLOWLOCATION => true,
// CURLOPT_SSL_VERIFYHOST => false,
// CURLOPT_SSL_VERIFYPEER => false,
// CURLOPT_MAXREDIRS => 5
];
if (($cookie = getenv('COOKIE')) != "") {
$curl_options[CURLOPT_COOKIE] = $cookie;
if ($payload) {
$default_opts[CURLOPT_POST] = 1;
$payload = is_bool($payload) ? [] : (is_array($payload) ? http_build_query($payload) : $payload);
$default_opts[CURLOPT_POSTFIELDS] = $payload;
}
if (getenv('USE_PROXY') == 'true') {
$curl_options[CURLOPT_PROXY] = getenv('PROXY_IP');
$curl_options[CURLOPT_PROXYPORT] = getenv('PROXY_PORT');
$default_opts[CURLOPT_PROXY] = getenv('PROXY_IP');
$default_opts[CURLOPT_PROXYPORT] = getenv('PROXY_PORT');
}
foreach ($tasks as $task) {
$payload = $task['payload'];
$header = is_null($headers) ? self::getHeaders(self::$headers) : self::getHeaders($headers);
$options = [
'header' => $header,
'post_data' => is_array($payload) ? http_build_query($payload) : $payload
];
$new_task = new HttpFuture($url, $options, $curl_options);
array_push($new_tasks, [
'task' => $new_task,
'source' => $task['source']
]);
}
foreach ($new_tasks as $new_task) {
Log::debug($url);
$result = $new_task['task']->fetch();
// var_dump($result);
array_push($results, [
'content' => $result,
'source' => $new_task['source']
]);
Log::debug($result);
}
return $results;
return $default_opts;
}
/**
* @use async
* @param $url
* @param array $tasks
* @param null $headers
* @param int $timeout
* @return array
*/
public static function asyncPost($url, $tasks = [], $headers = null, $timeout = 30)
{
$curl = self::getMultiClient(count($tasks));
$curl_options = self::fillCurlOpts($url, true, $headers, $timeout);
$curl->onTask = function ($curl) use ($curl_options, &$tasks) {
$task = array_shift($tasks);
if (is_null($task)) {
return;
}
$payload = $task['payload'];
$curl_options[CURLOPT_POSTFIELDS] = is_array($payload) ? http_build_query($payload) : $payload;
$curl->add([
'opt' => $curl_options,
'args' => $task['source'],
], function ($response, $args) {
Log::debug($response['info']['url']);
array_push(self::$results, [
'content' => $response['body'],
'source' => $args
]);
Log::debug($response['body']);
});
};
$curl->start();
return self::getResults();
}
/**
* @use post
* @param $url
* @param $payload
* @param null $headers
* @param int $timeout
* @return bool|string
* @throws \Exception
*/
public static function post($url, $payload = null, $headers = null, $timeout = 30)
{
$url = self::http2https($url);
@ -124,7 +210,7 @@ class Curl
}
if ($raw === false || strpos($raw, 'timeout') !== false) {
Log::warning('重试,获取的资源无效!');
Log::warning('获取的资源无效!');
$ret_count--;
continue;
}
@ -134,7 +220,7 @@ class Curl
return $raw;
} catch (\Exception $e) {
Log::warning("重试,Curl请求出错,{$e->getMessage()}!");
Log::warning("Curl请求出错, {$e->getMessage()}!");
$ret_count--;
continue;
}
@ -142,7 +228,16 @@ class Curl
exit('重试次数过多,请检查代码,退出!');
}
public static function other($url, $payload = null, $headers = null, $cookie = null, $timeout = 30)
/**
* @use request
* @param $url
* @param null $payload
* @param null $headers
* @param null $cookie
* @param int $timeout
* @return bool|string
*/
public static function request($url, $payload = null, $headers = null, $cookie = null, $timeout = 30)
{
Log::debug($url);
$header = is_null($headers) ? self::getHeaders(self::$headers) : self::getHeaders($headers);
@ -181,7 +276,7 @@ class Curl
}
if ($raw === false || strpos($raw, 'timeout') !== false) {
Log::warning('重试,获取的资源无效!');
Log::warning('获取的资源无效!');
$ret_count--;
continue;
}
@ -191,7 +286,7 @@ class Curl
return $raw;
} catch (\Exception $e) {
Log::warning("重试,Curl请求出错,{$e->getMessage()}!");
Log::warning("Curl请求出错, {$e->getMessage()}!");
$ret_count--;
continue;
}
@ -200,6 +295,14 @@ class Curl
}
/**
* @use get
* @param $url
* @param null $payload
* @param null $headers
* @return bool|string
* @throws \Exception
*/
public static function get($url, $payload = null, $headers = null)
{
if (!is_null($payload)) {

View File

@ -22,7 +22,7 @@ abstract class BaseRaffle
protected static $wait_list;
protected static $finish_list;
protected static $all_list;
protected static $room_stats = ['room_id' => 0, 'status' => false];
protected static $banned_rids = [];
public static function run()
{
@ -174,21 +174,24 @@ abstract class BaseRaffle
if (getenv(static::ACTIVE_SWITCH) == 'false') {
return false;
}
$current_rid = (int)$data['rid'];
// 去重
if (static::toRepeatLid($data['lid'], false)) {
if (static::toRepeatLid($current_rid, false)) {
return false;
}
// 钓鱼&&防止重复请求
if ($data['rid'] != static::$room_stats['room_id']) {
static::$room_stats = ['room_id' => $data['rid'], 'status' => Live::fishingDetection($data['rid'])];
// 拒绝钓鱼 防止重复请求
if (in_array($current_rid, static::$banned_rids)) {
return false;
}
if (static::$room_stats['status']) {
$banned_status = Live::fishingDetection($current_rid);
if ($banned_status) {
array_push(static::$banned_rids, $current_rid);
return false;
}
// 实际检测
$raffles_info = static::check($data['rid']);
$raffles_info = static::check($current_rid);
if (!empty($raffles_info)) {
static::parseLotteryInfo($data['rid'], $raffles_info);
static::parseLotteryInfo($current_rid, $raffles_info);
}
$wait_num = count(static::$wait_list);
if ($wait_num > 10 && ($wait_num % 2)) {
@ -196,7 +199,4 @@ abstract class BaseRaffle
}
return true;
}
}

View File

@ -10,10 +10,6 @@
namespace BiliHelper\Plugin;
use BiliHelper\Core\Log;
use BiliHelper\Core\Curl;
use BiliHelper\Util\TimeLock;
class DataTreating
{
// TODO 独立分发 Push||Pull数据

View File

@ -38,11 +38,11 @@ class Heart
$payload = [
'room_id' => getenv('ROOM_ID'),
];
$data = Curl::post('https://api.live.bilibili.com/User/userOnlineHeart', Sign::api($payload));
$data = Curl::post('https://api.live.bilibili.com/relation/v1/Feed/heartBeat', Sign::api($payload));
$data = json_decode($data, true);
if (isset($data['code']) && $data['code']) {
Log::warning('WEB端 直播间心跳停止惹~', ['msg' => $data['message']]);
Log::warning('WEB端 发送心跳异常!', ['msg' => $data['message']]);
} else {
Log::info('WEB端 发送心跳正常!');
}
@ -60,7 +60,7 @@ class Heart
$data = json_decode($data, true);
if (isset($data['code']) && $data['code']) {
Log::warning('APP端 直播间心跳停止惹~', ['msg' => $data['message']]);
Log::warning('APP端 发送心跳异常!', ['msg' => $data['message']]);
} else {
Log::info('APP端 发送心跳正常!');
}

View File

@ -18,16 +18,10 @@ class Live
{
use TimeLock;
public static function run()
{
return;
}
/**
* @use 获取分区列表
* @return array
* @throws \Exception
*/
public static function fetchLiveAreas(): array
{
@ -47,10 +41,12 @@ class Live
return $areas;
}
/**
* @use AREA_ID转ROOM_ID
* @param $area_id
* @return array
* @throws \Exception
*/
public static function areaToRid($area_id): array
{
@ -94,6 +90,7 @@ class Live
* @use 获取直播房间号
* @param $room_id
* @return bool
* @throws \Exception
*/
public static function getRealRoomID($room_id)
{
@ -131,23 +128,11 @@ class Live
}
/**
* @use 随机延迟
* @param int $min
* @param int $max
* @return bool
*/
public static function randDelay($min = 0, $max = 3): bool
{
$rand = $min + random_int() / mt_getrandmax() * ($max - $min);
sleep($rand);
return true;
}
/**
* @use 访问直播间
* @param $room_id
* @return bool
* @throws \Exception
*/
public static function goToRoom($room_id): bool
{

View File

@ -196,7 +196,7 @@ class Login
'Host' => 'passport.bilibili.com',
'Cookie' => 'sid=blhelper'
];
$data = Curl::other('https://passport.bilibili.com/captcha', null, $headers);
$data = Curl::request('https://passport.bilibili.com/captcha', null, $headers);
$data = base64_encode($data);
$captcha = self::ocrCaptcha($data);
return [
@ -219,7 +219,7 @@ class Login
$headers = [
'Content-Type' => 'application/json',
];
$data = Curl::other('http://47.102.120.84:19951/', json_encode($payload), $headers);
$data = Curl::request('http://47.102.120.84:19951/', json_encode($payload), $headers);
$de_raw = json_decode($data, true);
Log::info("验证码识别结果 {$de_raw['message']}");

View File

@ -24,10 +24,10 @@ class MasterSite
return;
}
if (self::watchAid() && self::shareAid() && self::coinAdd()) {
self::setLock( 24 * 60 * 60);
self::setLock(24 * 60 * 60);
return;
}
self::setLock( 3600);
self::setLock(3600);
}
@ -122,12 +122,12 @@ class MasterSite
$aid = !empty(getenv('ADD_COIN_AV')) ? getenv('ADD_COIN_AV') : self::getRandomAid();
self::reward($aid);
} else {
$coins = $av_num - self::coinLog();
if ($coins <= 0) {
$need_coins = $av_num - self::coinLog();
if ($need_coins <= 0) {
Log::info('今日投币上限已满!');
break;
}
$aids = self::getDayRankingAids($av_num);
$aids = self::getDayRankingAids($need_coins);
foreach ($aids as $aid) {
self::reward($aid);
}
@ -145,6 +145,7 @@ class MasterSite
/**
* @use 获取随机AID
* @return string
* @throws \Exception
*/
private static function getRandomAid(): string
{
@ -198,6 +199,7 @@ class MasterSite
/**
* @use 分享视频
* @return bool
* @throws \Exception
*/
private static function shareAid(): bool
{
@ -231,6 +233,7 @@ class MasterSite
/**
* @use 观看视频
* @return bool
* @throws \Exception
*/
private static function watchAid(): bool
{
@ -299,6 +302,7 @@ class MasterSite
/**
* @use 解析AID到CID
* @return array
* @throws \Exception
*/
private static function parseAid(): array
{
@ -316,14 +320,12 @@ class MasterSite
}
$cid = $de_raw['data']['cid'];
$duration = $de_raw['data']['duration'];
break;
return [
'aid' => $aid,
'cid' => $cid,
'duration' => $duration
];
}
return [
'aid' => $aid,
'cid' => $cid,
'duration' => $duration
];
}
}

View File

@ -121,6 +121,7 @@ class MaterialObject
// 过滤敏感词
$title = $response['data']['title'];
if (self::filterTitleWords($title)) {
array_push(self::$invalid_aids, $probe_aid);
continue;
}
// 过滤抽奖轮次

17
src/tool/DumpMemory.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace BiliHelper\Tool;
use BiliHelper\Core\Log;
class DumpMemory
{
public static function dd($title)
{
$unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
$size = memory_get_usage(true);
$memory = @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
Log::warning("{$title} # 内存 # {$memory}");
}
}