初始化基础模型

This commit is contained in:
kuaifan 2021-05-29 17:11:41 +08:00
parent e38f2ee2b6
commit 8e770b02fe
20 changed files with 32291 additions and 32 deletions

19687
_ide_helper.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
<?php
namespace App\Events;
use Hhxsv5\LaravelS\Swoole\Events\ServerStartInterface;
use Swoole\Http\Server;
class ServerStartEvent implements ServerStartInterface
{
public function __construct()
{
}
public function handle(Server $server)
{
$server->startMsecTime = $this->msecTime();
}
private function msecTime()
{
list($msec, $sec) = explode(' ', microtime());
$time = explode(".", $sec . ($msec * 1000));
return $time[0];
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Events;
use App\Models\WebSocket;
use Cache;
use Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface;
use Swoole\Http\Server;
class WorkerStartEvent implements WorkerStartInterface
{
public function __construct()
{
}
public function handle(Server $server, $workerId)
{
if (isset($server->startMsecTime) && Cache::get("swooleServerStartMsecTime") != $server->startMsecTime) {
Cache::forever("swooleServerStartMsecTime", $server->startMsecTime);
WebSocket::query()->delete();
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Http\Controllers;
use App\Module\Base;
use Redirect;
/**
* 页面
* Class IndexController
* @package App\Http\Controllers
*/
class IndexController extends InvokeController
{
/**
* 首页
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function main()
{
return view('main', ['version' => Base::getVersion()]);
}
/**
* 接口文档
* @return \Illuminate\Http\RedirectResponse
*/
public function api()
{
return Redirect::to(Base::fillUrl('docs/index.html'), 301);
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Module\Base;
use App\Tasks\IhttpTask;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Request;
class InvokeController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/**
* @param $method
* @param string $action
* @return array|void
*/
public function __invoke($method, $action = '')
{
$app = $method ?: 'main';
if ($action) {
$app .= "__" . $action;
}
// 接口不存在
if (!method_exists($this, $app)) {
$msg = "404 not found (" . str_replace("__", "/", $app) . ").";
return Base::ajaxError($msg);
}
// 使用websocket请求
$apiWebsocket = Request::header('Api-Websocket');
if ($apiWebsocket) {
$userid = User::token2userid();
if ($userid > 0) {
$url = 'http://127.0.0.1:' . env('LARAVELS_LISTEN_PORT') . Request::getRequestUri();
$task = new IhttpTask($url, Request::post(), [
'Content-Type' => Request::header('Content-Type'),
'language' => Request::header('language'),
'token' => Request::header('token'),
]);
$task->setApiWebsocket($apiWebsocket);
$task->setApiUserid($userid);
Task::deliver($task);
return Base::retSuccess('wait');
}
}
// 正常请求
$res = $this->__before($method, $action);
if ($res === true || Base::isSuccess($res)) {
return $this->$app();
} else {
return is_array($res) ? $res : Base::ajaxError($res);
}
}
/**
* @param $method
* @param $action
* @return bool|array|string
*/
public function __before($method, $action)
{
return true;
}
}

View File

@ -62,5 +62,7 @@ class Kernel extends HttpKernel
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'webapi' => \App\Http\Middleware\WebApi::class,
];
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
@error_reporting(E_ALL & ~E_NOTICE);
use Closure;
class WebApi
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
global $_A;
$_A = [];
return $next($request);
}
}

View File

@ -0,0 +1,180 @@
<?php
namespace App\Models;
use App\Module\Base;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
/**
* App\Model\AbstractModel
*
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel query()
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
* @method static \Illuminate\Database\Eloquent\Builder|static with($relations)
* @method static \Illuminate\Database\Query\Builder|static select($columns = [])
* @method static \Illuminate\Database\Query\Builder|static whereNotIn($column, $values, $boolean = 'and')
* @mixin \Eloquent
*/
class AbstractModel extends Model
{
use HasFactory;
const ID = 'id';
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
];
/**
* 获取模型主键的值(如果没有则先保存)
* @return mixed
*/
protected function scopeGetKeyValue()
{
$key = $this->getKeyName();
if (!isset($this->$key)) {
$this->save();
}
return $this->$key;
}
/**
* 为数组 / JSON 序列化准备日期。
* @param DateTimeInterface $date
* @return string
*/
protected function serializeDate(DateTimeInterface $date)
{
return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
}
/**
* 创建/更新数据
* @param array $param
* @param null $id
* @return AbstractModel|AbstractModel[]|\Illuminate\Database\Eloquent\Collection|Model|static
*/
public static function createInstance($param = [], $id = null)
{
if ($id) {
$instance = static::findOrFail($id);
} else {
$instance = new static;
}
if ($param) {
$instance->updateInstance($param);
}
return $instance;
}
/**
* 更新数据校验
* @param array $param
*/
public function updateInstance(array $param)
{
foreach ($param AS $k => $v) {
if (is_array($v)) {
$v = Base::array2json($v);
}
$this->$k = $v;
}
}
/**
* 根据条件更新数据
* @param $where
* @param $updateArray
* @return bool
*/
public static function updateData($where, $updateArray)
{
$isUpdate = false;
if ($updateArray) {
$result = self::transaction(function () use ($updateArray, $where) {
$list = static::where($where)->get();
if ($list->isNotEmpty()) {
foreach ($list AS $row) {
$row->updateInstance($updateArray);
$row->save();
}
}
});
$isUpdate = Base::isSuccess($result);
}
return $isUpdate;
}
/**
* 数据库更新或插入
* @param $where
* @param array $update 存在时更新的内容
* @param array $insert 不存在时插入的内容,如果没有则插入更新内容
* @return bool
*/
public static function updateInsert($where, $update = [], $insert = [])
{
$row = static::where($where)->first();
if (empty($row)) {
$row = new static;
$row->updateInstance(array_merge($where, $insert ?: $update));
} elseif ($update) {
$row->updateInstance($update);
}
return $row->save();
}
/**
* 定义变量为对象IDE高亮
* @param $value
* @return static
*/
public static function IDE($value)
{
return $value;
}
/**
* 用于Model的事务处理
* @param \Closure $closure
* @return array
*/
public static function transaction(\Closure $closure)
{
//开启事务
try {
DB::beginTransaction();
$result = $closure();
if (is_bool($result)) {
if ($result === false) {
throw new \Exception('处理失败!'); // 错误:① 返回faske
}
} elseif ($result) {
if (is_string($result)) {
throw new \Exception($result); // 错误:② 返回字符串(错误描述)
} elseif (is_array($result)
&& Base::isError($result)) {
throw new \Exception($result['msg']); // 错误:③ 返回数组且ret=0
}
}
DB::commit();
return $result ?: Base::retSuccess('success');
} catch (\Throwable $e) {
info($e);
//接收异常处理并回滚
try {
DB::rollBack();
} catch (\Throwable $eb) {
info($eb);
}
return Base::retError($e->getMessage() ?: '处理错误!');
}
}
}

12
app/Models/Setting.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
/**
* Class Setting
* @package App\Models
*/
class Setting extends AbstractModel
{
}

12
app/Models/Tmp.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
/**
* Class Tmp
* @package App\Models
*/
class Tmp extends AbstractModel
{
}

View File

@ -2,42 +2,344 @@
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
use App\Module\Base;
use Cache;
/**
* Class User
* @package App\Models
*/
class User extends AbstractModel
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
'encrypt',
'userpass',
];
/**
* The attributes that should be cast to native types.
*
* @var array
* 昵称
* @param $value
* @return string
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getNicknameAttribute($value)
{
return $value ?: $this->username;
}
/**
* 头像地址
* @param $value
* @return string
*/
public function getUseringAttribute($value)
{
return self::userimg($value);
}
/**
* 身份权限
* @param $value
* @return array
*/
public function getIdentityAttribute($value)
{
return is_array($value) ? $value : explode(",", trim($value, ","));
}
/**
* userid获取用户名
* @param $userid
* @return mixed
*/
public static function userid2username($userid)
{
if (empty($userid)) {
return '';
}
return self::whereUserid(intval($userid))->value('username');
}
/**
* 用户名获取userid
* @param $username
* @return int
*/
public static function username2userid($username)
{
if (empty($username)) {
return 0;
}
return intval(self::whereUsername($username)->value('userid'));
}
/**
* token获取会员userid
* @return int
*/
public static function token2userid()
{
return self::authFind('userid', Base::getToken());
}
/**
* token获取会员账号
* @return int
*/
public static function token2username()
{
return self::authFind('username', Base::getToken());
}
/**
* token获取encrypt
* @return mixed|string
*/
public static function token2encrypt()
{
return self::authFind('encrypt', Base::getToken());
}
/**
* 获取token身份信息
* @param $find
* @param null $token
* @return array|mixed|string
*/
public static function authFind($find, $token = null)
{
if ($token === null) {
$token = Base::getToken();
}
list($userid, $username, $encrypt, $timestamp) = explode("@", base64_decode($token) . "@@@@");
$array = [
'userid' => intval($userid),
'username' => $username ?: '',
'encrypt' => $encrypt ?: '',
'timestamp' => intval($timestamp),
];
if (isset($array[$find])) {
return $array[$find];
}
if ($find == 'all') {
return $array;
}
return '';
}
/**
* 用户身份认证(获取用户信息)
* @return array|mixed
*/
public static function auth()
{
global $_A;
if (isset($_A["__static_auth"])) {
return $_A["__static_auth"];
}
$authorization = Base::getToken();
if ($authorization) {
$authInfo = self::authFind('all', $authorization);
if ($authInfo['userid'] > 0) {
$loginValid = floatval(Base::settingFind('system', 'loginValid')) ?: 720;
$loginValid *= 3600;
if ($authInfo['timestamp'] + $loginValid > time()) {
$row = self::whereUserid($authInfo['userid'])->whereUsername($authInfo['username'])->whereEncrypt($authInfo['encrypt'])->first();
if ($row) {
if ($row->token) {
$timestamp = self::authFind('timestamp', $row->token);
if ($timestamp + $loginValid > time()) {
$upArray = [];
if (Base::getIp() && $row->lineip != Base::getIp()) {
$upArray['lineip'] = Base::getIp();
}
if ($row->linedate + 30 < time()) {
$upArray['linedate'] = time();
}
if ($upArray) {
$row->updateInstance($upArray);
$row->save();
}
return $_A["__static_auth"] = $row;
}
}
}
}
}
}
return $_A["__static_auth"] = false;
}
/**
* 用户身份认证(获取用户信息)
* @return array
*/
public static function authE()
{
$user = self::auth();
if (!$user) {
$authorization = Base::getToken();
if ($authorization) {
return Base::retError('身份已失效,请重新登录!', $user, -1);
} else {
return Base::retError('请登录后继续...', [], -1);
}
}
return Base::retSuccess("auth", $user);
}
/**
* 生成token
* @param $userinfo
* @return string
*/
public static function token($userinfo)
{
return base64_encode($userinfo['userid'] . '@' . $userinfo['username'] . '@' . $userinfo['encrypt'] . '@' . time() . '@' . Base::generatePassword(6));
}
/**
* 判断用户权限(身份)
* @param $identity
* @return array
*/
public static function identity($identity)
{
$user = self::auth();
if (is_array($user->identity)
&& in_array($identity, $user->identity)) {
return Base::retSuccess("success");
}
return Base::retError("权限不足!");
}
/**
* 判断用户权限(身份)
* @param $identity
* @return bool
*/
public static function identityCheck($identity)
{
if (is_array($identity)) {
foreach ($identity as $id) {
if (!Base::isError(self::identity($id)))
return true;
}
return false;
}
return Base::isSuccess(self::identity($identity));
}
/**
* 判断用户权限(身份)
* @param $identity
* @param $userIdentity
* @return bool
*/
public static function identityRaw($identity, $userIdentity)
{
$userIdentity = is_array($userIdentity) ? $userIdentity : explode(",", trim($userIdentity, ","));
return $identity && in_array($identity, $userIdentity);
}
/**
* userid 获取 基本信息
* @param int $userid 会员ID
* @return array
*/
public static function userid2basic(int $userid)
{
global $_A;
if (empty($userid)) {
return [];
}
if (isset($_A["__static_userid2basic_" . $userid])) {
return $_A["__static_userid2basic_" . $userid];
}
$fields = ['userid', 'username', 'nickname', 'userimg'];
$userInfo = self::whereUserid($userid)->select($fields)->first();
if ($userInfo) {
$userInfo->userimg = self::userimg($userInfo->userimg);
}
return $_A["__static_userid2basic_" . $userid] = ($userInfo ?: []);
}
/**
* username 获取 基本信息
* @param string $username 用户名
* @return array
*/
public static function username2basic(string $username)
{
global $_A;
if (empty($username)) {
return [];
}
if (isset($_A["__static_username2basic_" . $username])) {
return $_A["__static_username2basic_" . $username];
}
$fields = ['userid', 'username', 'nickname', 'userimg'];
$userInfo = self::whereUsername($username)->select($fields)->first();
if ($userInfo) {
$userInfo->userimg = self::userimg($userInfo->userimg);
}
return $_A["__static_username2basic_" . $username] = ($userInfo ?: []);
}
/**
* 用户头像,不存在时返回默认
* @param string $var 头像地址 会员用户名
* @return string
*/
public static function userimg(string $var)
{
if (!Base::strExists($var, '.')) {
if (empty($var)) {
$var = "";
} else {
$userInfo = self::username2basic($var);
$var = $userInfo['userimg'];
}
}
return $var ? Base::fillUrl($var) : url('images/other/avatar.png');
}
/**
* 更新首字母
* @param $userid
*/
public static function AZUpdate($userid)
{
$row = self::whereUserid($userid)->select(['username', 'nickname'])->first();
if ($row) {
$row->az = Base::getFirstCharter($row->nickname);
$row->save();
}
}
/**
* 是否需要验证码
* @param $username
* @return array
*/
public static function needCode($username)
{
$loginCode = Base::settingFind('system', 'loginCode');
switch ($loginCode) {
case 'open':
return Base::retSuccess('need');
case 'close':
return Base::retError('no');
default:
if (Cache::get("code::" . $username) == 'need') {
return Base::retSuccess('need');
} else {
return Base::retError('no');
}
}
}
}

12
app/Models/WebSocket.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
/**
* Class WebSocket
* @package App\Model
*/
class WebSocket extends AbstractModel
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
/**
* Class WebSocketTmpMsg
* @package App\Models
*/
class WebSocketTmpMsg extends AbstractModel
{
}

2795
app/Module/Base.php Executable file

File diff suppressed because it is too large Load Diff

288
app/Module/Ihttp.php Executable file
View File

@ -0,0 +1,288 @@
<?php
namespace App\Module;
use Exception;
@error_reporting(E_ALL & ~E_NOTICE);
class Ihttp
{
public static function ihttp_request($url, $post = [], $extra = [], $timeout = 60, $retRaw = false, $isGb2312 = false) {
$urlset = parse_url($url);
if(empty($urlset['path'])) {
$urlset['path'] = '/';
}
if(!empty($urlset['query'])) {
$urlset['query'] = "?{$urlset['query']}";
}
if(empty($urlset['port'])) {
$urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
}
if (Base::strExists($url, 'https://') && !extension_loaded('openssl')) {
if (!extension_loaded("openssl")) {
return Base::retError('请开启您PHP环境的openssl');
}
}
Base::addLog([
'url' => $url,
'post' => $post,
], 'before_' . $url);
if (function_exists('curl_init') && function_exists('curl_exec')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $urlset['scheme']. '://' .$urlset['host'].($urlset['port'] == '80' ? '' : ':'.$urlset['port']).$urlset['path'].$urlset['query']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
if($post) {
if (is_array($post)) {
$filepost = false;
foreach ($post as $name => $value) {
if (is_string($value) && substr($value, 0, 1) == '@') {
$filepost = true;
break;
}
}
if (!$filepost) {
$post = http_build_query($post);
}
}
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
if (defined('CURL_SSLVERSION_TLSv1')) {
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
}
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
if (!empty($extra) && is_array($extra)) {
$headers = array();
foreach ($extra as $opt => $value) {
if (Base::strExists($opt, 'CURLOPT_')) {
curl_setopt($ch, constant($opt), $value);
} elseif (is_numeric($opt)) {
curl_setopt($ch, $opt, $value);
} else {
$headers[] = "{$opt}: {$value}";
}
}
if(!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
}
$data = curl_exec($ch);
//$status = curl_getinfo($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if($errno || empty($data)) {
Base::addLog([
'url' => $url,
'post' => $post,
'error' => $error,
], 'error_' . $url);
return Base::retError($error);
} else {
if ($isGb2312) {
try { $data = iconv('GB2312', 'UTF-8', $data); }catch (Exception $e) { }
}
$response = self::ihttp_response_parse($data);
Base::addLog([
'url' => $url,
'post' => $post,
'response' => $response,
], 'success_' . $url);
if ($retRaw === true) {
return Base::retSuccess($response['code'], $response);
}
return Base::retSuccess($response['code'], $response['content']);
}
}
$method = empty($post) ? 'GET' : 'POST';
$fdata = "{$method} {$urlset['path']}{$urlset['query']} HTTP/1.1\r\n";
$fdata .= "Host: {$urlset['host']}\r\n";
if(function_exists('gzdecode')) {
$fdata .= "Accept-Encoding: gzip, deflate\r\n";
}
$fdata .= "Connection: close\r\n";
if (!empty($extra) && is_array($extra)) {
foreach ($extra as $opt => $value) {
if (!Base::strExists($opt, 'CURLOPT_')) {
$fdata .= "{$opt}: {$value}\r\n";
}
}
}
//$body = '';
if ($post) {
if (is_array($post)) {
$body = http_build_query($post);
} else {
$body = urlencode((string)$post);
}
$fdata .= 'Content-Length: ' . strlen($body) . "\r\n\r\n{$body}";
} else {
$fdata .= "\r\n";
}
if($urlset['scheme'] == 'https') {
$fp = fsockopen('ssl://' . $urlset['host'], $urlset['port'], $errno, $error);
} else {
$fp = fsockopen($urlset['host'], $urlset['port'], $errno, $error);
}
stream_set_blocking($fp, true);
stream_set_timeout($fp, $timeout);
if (!$fp) {
Base::addLog([
'url' => $url,
'post' => $post,
'error' => $error,
], 'error_' . $url);
return Base::retError( $error);
} else {
fwrite($fp, $fdata);
$content = '';
while (!feof($fp))
$content .= fgets($fp, 512);
fclose($fp);
if ($isGb2312) {
try { $content = iconv('GB2312', 'UTF-8', $content); }catch (Exception $e) { }
}
$response = self::ihttp_response_parse($content, true);
Base::addLog([
'url' => $url,
'post' => $post,
'response' => $response,
], 'success_' . $url);
if ($retRaw === true) {
return Base::retSuccess($response['code'], $response);
}
return Base::retSuccess($response['code'], $response['content']);
}
}
public static function ihttp_get($url) {
return self::ihttp_request($url);
}
public static function ihttp_post($url, $data, $timeout = 60) {
$headers = array('Content-Type' => 'application/x-www-form-urlencoded');
return self::ihttp_request($url, $data, $headers, $timeout);
}
public static function ihttp_proxy($url, $post = [], $timeout = 20, $extra = []) {
return self::ihttp_request($url, $post, $extra, $timeout);
}
private static function ihttp_response_parse($data, $chunked = false) {
$rlt = array();
$pos = strpos($data, "\r\n\r\n");
if (Base::strExists(substr($data, 0, $pos), "Proxy-agent:")) {
$data = substr($data, $pos + 4, strlen($data));
$pos = strpos($data, "\r\n\r\n");
}
$split1[0] = substr($data, 0, $pos);
$split1[1] = substr($data, $pos + 4, strlen($data));
$split2 = explode("\r\n", $split1[0], 2);
preg_match('/^(\S+) (\S+) (\S+)$/', $split2[0], $matches);
$rlt['code'] = $matches[2];
$rlt['status'] = $matches[3];
$rlt['responseline'] = $split2[0];
$header = explode("\r\n", $split2[1]);
$isgzip = false;
$ischunk = false;
foreach ($header as $v) {
$row = explode(':', $v);
$key = trim($row[0]);
$value = trim(substr($v, strlen($row[0]) + 1));
if (is_array($rlt['headers'][$key])) {
$rlt['headers'][$key][] = $value;
} elseif (!empty($rlt['headers'][$key])) {
$temp = $rlt['headers'][$key];
unset($rlt['headers'][$key]);
$rlt['headers'][$key][] = $temp;
$rlt['headers'][$key][] = $value;
} else {
$rlt['headers'][$key] = $value;
}
if(!$isgzip && strtolower($key) == 'content-encoding' && strtolower($value) == 'gzip') {
$isgzip = true;
}
if(!$ischunk && strtolower($key) == 'transfer-encoding' && strtolower($value) == 'chunked') {
$ischunk = true;
}
}
if($chunked && $ischunk) {
$rlt['content'] = self::ihttp_response_parse_unchunk($split1[1]);
} else {
$rlt['content'] = $split1[1];
}
if($isgzip && function_exists('gzdecode')) {
$rlt['content'] = gzdecode($rlt['content']);
}
$rlt['meta'] = $data;
if($rlt['code'] == '100') {
return self::ihttp_response_parse($rlt['content']);
}
return $rlt;
}
private static function ihttp_response_parse_unchunk($str = null) {
if(!is_string($str) or strlen($str) < 1) {
return false;
}
$eol = "\r\n";
$add = strlen($eol);
$tmp = $str;
$str = '';
do {
$tmp = ltrim($tmp);
$pos = strpos($tmp, $eol);
if($pos === false) {
return false;
}
$len = hexdec(substr($tmp, 0, $pos));
if(!is_numeric($len) or $len < 0) {
return false;
}
$str .= substr($tmp, ($pos + $add), $len);
$tmp = substr($tmp, ($len + $pos + $add));
$check = trim($tmp);
} while(!empty($check));
unset($tmp);
return $str;
}
/**
* 下载文件到服务器本地
* @param string $url 下载地址
* @param string $fileFile 保存文件路径
* @return array
*/
public static function download(string $url, string $fileFile)
{
if ($url == '') {
return Base::retError("url error");
}
// 获取远程文件资源
$ch = curl_init();
$timeout = 30;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$file = curl_exec($ch);
curl_close($ch);
// 保存文件
$res = fopen($fileFile, 'a');
fwrite($res, $file);
fclose($res);
return Base::retSuccess('success');
}
}

8469
app/Module/IpAddr/all_cn.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
<?php
namespace App\Tasks;
use Hhxsv5\LaravelS\Swoole\Task\Task;
/**
* Class AbstractTask
* @package App\Tasks
*/
abstract class AbstractTask extends Task
{
protected $newTask = [];
/**
* 添加完成后执行的任务
* @param $task
*/
final protected function addTask($task)
{
$this->newTask[] = $task;
}
/**
* 包装执行过程
*/
final public function handle()
{
try {
$this->start();
} catch (\Exception $e) {
$this->info($e);
$this->failed($e);
}
}
/**
* 开始执行任务
*/
abstract public function start();
/**
* 任务完成事件
*/
public function finish()
{
foreach ($this->newTask AS $task) {
Task::deliver($task);
}
}
/**
* 任务失败事件
* @param $e
*/
public function failed($e)
{
//
}
/**
* 添加日志
* @param $var
*/
private function info($var)
{
if (!config('app.debug') || defined('DO_NOT_ADD_LOGS')) {
return;
}
info($var);
}
}

67
app/Tasks/IhttpTask.php Normal file
View File

@ -0,0 +1,67 @@
<?php
namespace App\Tasks;
@error_reporting(E_ALL & ~E_NOTICE);
use App\Module\Base;
use App\Module\Ihttp;
/**
* Ihttp任务
* Class IhttpTask
* @package App\Tasks
*/
class IhttpTask extends AbstractTask
{
protected $url;
protected $post;
protected $extra;
protected $apiWebsocket;
protected $apiUserid;
/**
* IhttpTask constructor.
* @param $url
* @param array $post
* @param array $extra
*/
public function __construct($url, $post = [], $extra = [])
{
$this->url = $url;
$this->post = $post;
$this->extra = $extra;
}
/**
* @param mixed $apiWebsocket
*/
public function setApiWebsocket($apiWebsocket): void
{
$this->apiWebsocket = $apiWebsocket;
}
/**
* @param mixed $apiUserid
*/
public function setApiUserid($apiUserid): void
{
$this->apiUserid = $apiUserid;
}
public function start()
{
$res = Ihttp::ihttp_request($this->url, $this->post, $this->extra);
if ($this->apiWebsocket && $this->apiUserid) {
$body = Base::isSuccess($res) ? Base::json2array($res['data']) : $res;
PushTask::push([
'userid' => $this->apiUserid,
'msg' => [
'messageType' => 'apiWebsocket',
'apiWebsocket' => $this->apiWebsocket,
'apiSuccess' => Base::isSuccess($res),
'body' => $body,
]
]);
}
}
}

167
app/Tasks/PushTask.php Normal file
View File

@ -0,0 +1,167 @@
<?php
namespace App\Tasks;
@error_reporting(E_ALL & ~E_NOTICE);
use App\Models\WebSocket;
use App\Models\WebSocketTmpMsg;
use App\Module\Base;
use Cache;
use Carbon\Carbon;
use Hhxsv5\LaravelS\Swoole\Task\Task;
/**
* 发送消息任务
* Class PushTask
* @package App\Tasks
*/
class PushTask extends AbstractTask
{
protected $params;
/**
* PushTask constructor.
* @param string|array $params
*/
public function __construct($params = [])
{
$this->params = $params;
}
public function start()
{
if (is_string($this->params)) {
$key = $this->params;
$params = Cache::pull($key);
if (is_array($params) && $params['fd']) {
$this->params = [$params];
}
}
is_array($this->params) && self::push($this->params);
}
/**
* 记录发送失败的消息,等上线后重新发送
* @param array $userFail
* @param array $msg
*/
private static function addTmpMsg(array $userFail, array $msg)
{
foreach ($userFail as $uid) {
$msgString = Base::array2json($msg);
$inArray = [
'md5' => md5($uid . '-' . $msgString),
'msg' => $msgString,
'send' => 0,
'create_id' => $uid,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
if (!WebSocketTmpMsg::whereMd5($inArray['md5'])->exists()) {
WebSocketTmpMsg::insertOrIgnore($inArray);
}
}
}
/**
* 根据会员ID重试发送失败的消息
* @param $userid
*/
public static function resendTmpMsgForUserid($userid)
{
$lists = WebSocketTmpMsg::whereCreateId($userid)
->whereSend(0)
->where('created_at', '>', Carbon::now()->subMinute()) // 1分钟内添加的数据
->orderBy('id')
->get();
if ($lists->isNotEmpty()) {
foreach ($lists as $item) {
self::push([
'tmp_msg_id' => $item->id,
'userid' => $userid,
'msg' => Base::json2array($item->msg),
]);
}
}
}
/**
* 推送消息
* @param array $lists 消息列表
* @param string|int $key 延迟推送key依据留空立即推送延迟推送时发给同一人同一种消息类型只发送最新的一条
* @param int $delay 延迟推送时间默认1秒$key填写时有效
*/
public static function push(array $lists, $key = '', $delay = 1)
{
if (!is_array($lists) || empty($lists)) {
return;
}
if (!Base::isTwoArray($lists)) {
$lists = [$lists];
}
$swoole = app('swoole');
foreach ($lists AS $item) {
if (!is_array($item) || empty($item)) {
continue;
}
$userid = $item['userid'];
$fd = $item['fd'];
$msg = $item['msg'];
$tmp_msg_id = intval($item['tmp_msg_id']);
if (!is_array($msg)) {
continue;
}
$messageType = $msg['messageType'];
if (empty($messageType)) {
continue;
}
// 发送对象
$userFail = [];
$array = [];
if ($fd) {
if (is_array($fd)) {
$array = array_merge($array, $fd);
} else {
$array[] = $fd;
}
}
if ($userid) {
if (!is_array($userid)) {
$userid = [$userid];
}
foreach ($userid as $uid) {
$row = WebSocket::select(['fd'])->whereUserid($uid)->pluck('fd');
if ($row->isNotEmpty()) {
$array = array_merge($array, $row->toArray());
} else {
$userFail[] = $uid;
}
}
}
// 开始发送
foreach ($array as $fid) {
if (empty($key)) {
try {
$swoole->push($fid, Base::array2json($msg));
$tmp_msg_id > 0 && WebSocketTmpMsg::whereId($tmp_msg_id)->update(['send' => 1]);
} catch (\Exception $e) {
$userFail[] = WebSocket::whereFd($fid)->value('userid');
}
} else {
$key = "PUSH::" . $fid . ":" . $messageType . ":" . $key;
Cache::put($key, [
'fd' => $fid,
'msg' => $msg,
]);
$task = new PushTask($key);
$task->delay($delay);
Task::deliver($task);
}
}
// 记录发送失败的
$userFail = array_values(array_unique($userFail));
$tmp_msg_id == 0 && self::addTmpMsg($userFail, $msg);
}
}
}

View File

@ -18,7 +18,11 @@
"madnest/madzipper": "^v1.0.5",
"mews/captcha": "^3.2.0",
"predis/predis": "^1.1.6",
"ext-json": "*"
"ext-json": "*",
"ext-simplexml": "*",
"ext-libxml": "*",
"ext-gd": "*",
"ext-curl": "*"
},
"require-dev": {
"barryvdh/laravel-ide-helper": "^2.8.1",