ComposerUpdate

This commit is contained in:
Anyon 2019-12-24 17:22:36 +08:00
parent 9890c4891f
commit 8cd55cb49d
38 changed files with 484 additions and 356 deletions

28
composer.lock generated
View File

@ -558,16 +558,16 @@
},
{
"name": "topthink/framework",
"version": "v6.0.0",
"version": "v6.0.1",
"source": {
"type": "git",
"url": "https://github.com/top-think/framework.git",
"reference": "79c555aab0313d1a33ddcdb3c395f2c47f37f597"
"reference": "501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/top-think/framework/zipball/79c555aab0313d1a33ddcdb3c395f2c47f37f597",
"reference": "79c555aab0313d1a33ddcdb3c395f2c47f37f597",
"url": "https://api.github.com/repos/top-think/framework/zipball/501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f",
"reference": "501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f",
"shasum": "",
"mirrors": [
{
@ -622,7 +622,7 @@
"orm",
"thinkphp"
],
"time": "2019-10-23T23:28:43+00:00"
"time": "2019-12-24T07:57:03+00:00"
},
{
"name": "topthink/think-helper",
@ -721,16 +721,16 @@
},
{
"name": "topthink/think-orm",
"version": "v2.0.28",
"version": "v2.0.29",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-orm.git",
"reference": "ff5f112f5559497222f2716385b5a709ab82741b"
"reference": "37cde31af3725cf5460ad8dc18032326b88e6310"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/ff5f112f5559497222f2716385b5a709ab82741b",
"reference": "ff5f112f5559497222f2716385b5a709ab82741b",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/37cde31af3725cf5460ad8dc18032326b88e6310",
"reference": "37cde31af3725cf5460ad8dc18032326b88e6310",
"shasum": "",
"mirrors": [
{
@ -768,7 +768,7 @@
"database",
"orm"
],
"time": "2019-11-17T07:53:45+00:00"
"time": "2019-12-23T13:50:01+00:00"
},
{
"name": "topthink/think-template",
@ -909,12 +909,12 @@
"source": {
"type": "git",
"url": "https://github.com/zoujingli/ThinkLibrary.git",
"reference": "60807fa6416e2b9d30ee785d37c0e90f4eab5ea2"
"reference": "9952e50062d5d8f447680cea4a557155b7353158"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/60807fa6416e2b9d30ee785d37c0e90f4eab5ea2",
"reference": "60807fa6416e2b9d30ee785d37c0e90f4eab5ea2",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/9952e50062d5d8f447680cea4a557155b7353158",
"reference": "9952e50062d5d8f447680cea4a557155b7353158",
"shasum": "",
"mirrors": [
{
@ -958,7 +958,7 @@
],
"description": "ThinkPHP v6.0 Development Library",
"homepage": "http://framework.thinkadmin.top",
"time": "2019-12-23T09:51:18+00:00"
"time": "2019-12-24T02:28:27+00:00"
},
{
"name": "zoujingli/wechat-developer",

View File

@ -569,17 +569,17 @@
},
{
"name": "topthink/framework",
"version": "v6.0.0",
"version_normalized": "6.0.0.0",
"version": "v6.0.1",
"version_normalized": "6.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/framework.git",
"reference": "79c555aab0313d1a33ddcdb3c395f2c47f37f597"
"reference": "501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/top-think/framework/zipball/79c555aab0313d1a33ddcdb3c395f2c47f37f597",
"reference": "79c555aab0313d1a33ddcdb3c395f2c47f37f597",
"url": "https://api.github.com/repos/top-think/framework/zipball/501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f",
"reference": "501f3dd17dc6266e17b7d8df3e9fd090bd2cc85f",
"shasum": "",
"mirrors": [
{
@ -606,7 +606,7 @@
"mockery/mockery": "^1.2",
"phpunit/phpunit": "^7.0"
},
"time": "2019-10-23T23:28:43+00:00",
"time": "2019-12-24T07:57:03+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -738,17 +738,17 @@
},
{
"name": "topthink/think-orm",
"version": "v2.0.28",
"version_normalized": "2.0.28.0",
"version": "v2.0.29",
"version_normalized": "2.0.29.0",
"source": {
"type": "git",
"url": "https://github.com/top-think/think-orm.git",
"reference": "ff5f112f5559497222f2716385b5a709ab82741b"
"reference": "37cde31af3725cf5460ad8dc18032326b88e6310"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/ff5f112f5559497222f2716385b5a709ab82741b",
"reference": "ff5f112f5559497222f2716385b5a709ab82741b",
"url": "https://api.github.com/repos/top-think/think-orm/zipball/37cde31af3725cf5460ad8dc18032326b88e6310",
"reference": "37cde31af3725cf5460ad8dc18032326b88e6310",
"shasum": "",
"mirrors": [
{
@ -764,7 +764,7 @@
"psr/simple-cache": "^1.0",
"topthink/think-helper": "^3.1"
},
"time": "2019-11-17T07:53:45+00:00",
"time": "2019-12-23T13:50:01+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -935,12 +935,12 @@
"source": {
"type": "git",
"url": "https://github.com/zoujingli/ThinkLibrary.git",
"reference": "60807fa6416e2b9d30ee785d37c0e90f4eab5ea2"
"reference": "9952e50062d5d8f447680cea4a557155b7353158"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/60807fa6416e2b9d30ee785d37c0e90f4eab5ea2",
"reference": "60807fa6416e2b9d30ee785d37c0e90f4eab5ea2",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/9952e50062d5d8f447680cea4a557155b7353158",
"reference": "9952e50062d5d8f447680cea4a557155b7353158",
"shasum": "",
"mirrors": [
{
@ -956,7 +956,7 @@
"ext-json": "*",
"topthink/framework": "^6.0"
},
"time": "2019-12-23T09:51:18+00:00",
"time": "2019-12-24T02:28:27+00:00",
"type": "library",
"extra": {
"think": {

2
vendor/services.php vendored
View File

@ -1,5 +1,5 @@
<?php
// This file is automatically generated at:2019-12-23 18:34:59
// This file is automatically generated at:2019-12-24 17:22:31
declare (strict_types = 1);
return array (
0 => 'think\\app\\Service',

View File

@ -38,7 +38,7 @@ ThinkPHP6.0底层架构采用PHP7.1改写和进一步优化。
## 安装
~~~
composer create-project topthink/think tp 6.0.*-dev
composer create-project topthink/think tp
~~~
启动服务

View File

@ -370,7 +370,7 @@ if (!function_exists('redirect')) {
* @param int $code 状态码
* @return \think\response\Redirect
*/
function redirect(string $url, int $code = 302): Redirect
function redirect(string $url = '', int $code = 302): Redirect
{
return Response::create($url, 'redirect', $code);
}
@ -523,7 +523,7 @@ if (!function_exists('validate')) {
} else {
if (strpos($validate, '.')) {
// 支持场景
list($validate, $scene) = explode('.', $validate);
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : app()->parseClass('validate', $validate);

View File

@ -39,7 +39,7 @@ use think\initializer\RegisterService;
*/
class App extends Container
{
const VERSION = '6.0.0';
const VERSION = '6.0.1';
/**
* 应用调试模式

View File

@ -304,7 +304,8 @@ class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, C
{
if (is_array($method)) {
[$class, $method] = $method;
$class = is_object($class) ? $class : $this->invokeClass($class);
$class = is_object($class) ? $class : $this->invokeClass($class);
} else {
// 静态方法
[$class, $method] = explode('::', $method);
@ -314,8 +315,7 @@ class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, C
$reflect = new ReflectionMethod($class, $method);
} catch (ReflectionException $e) {
$class = is_object($class) ? get_class($class) : $class;
$message = sprintf('method not exists: %d::%d()', $class, $method);
throw new FuncNotFoundException($message, "{$class}::{$method}", $e);
throw new FuncNotFoundException('method not exists: ' . $class . '::' . $method . '()', "{$class}::{$method}", $e);
}
$args = $this->bindParams($reflect, $vars);

View File

@ -35,6 +35,8 @@ class Cookie
'secure' => false,
// httponly设置
'httponly' => false,
// samesite 设置,支持 'strict' 'lax'
'samesite' => '',
];
/**
@ -181,9 +183,18 @@ class Cookie
public function save(): void
{
foreach ($this->cookie as $name => $val) {
list($value, $expire, $option) = $val;
[$value, $expire, $option] = $val;
$this->saveCookie($name, $value, $expire, $option['path'], $option['domain'], $option['secure'] ? true : false, $option['httponly'] ? true : false);
$this->saveCookie(
$name,
$value,
$expire,
$option['path'],
$option['domain'],
$option['secure'] ? true : false,
$option['httponly'] ? true : false,
$option['samesite']
);
}
}
@ -197,11 +208,23 @@ class Cookie
* @param string $domain 有效域名/子域名
* @param bool $secure 是否仅仅通过HTTPS
* @param bool $httponly 仅可通过HTTP访问
* @param string $samesite 防止CSRF攻击和用户追踪
* @return void
*/
protected function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly): void
protected function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly, string $samesite): void
{
setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
setcookie($name, $value, [
'expires' => $expire,
'path' => $path,
'domain' => $domain,
'secure' => $secure,
'httponly' => $httponly,
'samesite' => $samesite,
]);
} else {
setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
}
}
}

View File

@ -253,6 +253,7 @@ class Event
$result = [];
$listeners = $this->listener[$event] ?? [];
$listeners = array_unique($listeners, SORT_REGULAR);
foreach ($listeners as $key => $listener) {
$result[$key] = $this->dispatch($listener, $params);

View File

@ -100,13 +100,13 @@ class File extends SplFileInfo
set_error_handler(function ($type, $msg) use (&$error) {
$error = $msg;
});
$renamed = rename($this->getPathname(), $target);
$renamed = rename($this->getPathname(), (string) $target);
restore_error_handler();
if (!$renamed) {
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
}
@chmod($target, 0666 & ~umask());
@chmod((string) $target, 0666 & ~umask());
return $target;
}

View File

@ -169,7 +169,7 @@ class Lang
$range = $range ?: $this->range;
if ($this->config['allow_group'] && strpos($name, '.')) {
list($name1, $name2) = explode('.', $name, 2);
[$name1, $name2] = explode('.', $name, 2);
return isset($this->lang[$range][strtolower($name1)][$name2]);
}
@ -194,7 +194,7 @@ class Lang
}
if ($this->config['allow_group'] && strpos($name, '.')) {
list($name1, $name2) = explode('.', $name, 2);
[$name1, $name2] = explode('.', $name, 2);
$value = $this->lang[$range][strtolower($name1)][$name2] ?? $name;
} else {

View File

@ -135,7 +135,7 @@ class Middleware
return (new Pipeline())
->through(array_map(function ($middleware) {
return function ($request, $next) use ($middleware) {
list($call, $param) = $middleware;
[$call, $param] = $middleware;
if (is_array($call) && is_string($call[0])) {
$call = [$this->app->make($call[0]), $call[1]];
}
@ -158,7 +158,7 @@ class Middleware
{
foreach ($this->queue as $queue) {
foreach ($queue as $middleware) {
list($call) = $middleware;
[$call] = $middleware;
if (is_array($call) && is_string($call[0])) {
$instance = $this->app->make($call[0]);
if (method_exists($instance, 'end')) {
@ -197,7 +197,7 @@ class Middleware
protected function buildMiddleware($middleware, string $type): array
{
if (is_array($middleware)) {
list($middleware, $param) = $middleware;
[$middleware, $param] = $middleware;
}
if ($middleware instanceof Closure) {
@ -248,7 +248,7 @@ class Middleware
*/
protected function getMiddlewarePriority($priority, $middleware)
{
list($call) = $middleware;
[$call] = $middleware;
if (is_array($call) && is_string($call[0])) {
$index = array_search($call[0], array_reverse($priority));
return false === $index ? -1 : $index;

View File

@ -307,15 +307,6 @@ class Request
{
$request = new static();
$request->server = $_SERVER;
$request->env = $app->env;
$request->get = $_GET;
$request->post = $_POST ?: $request->getInputData($request->input);
$request->put = $request->getInputData($request->input);
$request->request = $_REQUEST;
$request->cookie = $_COOKIE;
$request->file = $_FILES ?? [];
if (function_exists('apache_request_headers') && $result = apache_request_headers()) {
$header = $result;
} else {
@ -337,6 +328,15 @@ class Request
$request->header = array_change_key_case($header);
$request->server = $_SERVER;
$request->env = $app->env;
$request->get = $_GET;
$request->post = $_POST ?: $request->getInputData($request->input);
$request->put = $request->getInputData($request->input);
$request->request = $_REQUEST;
$request->cookie = $_COOKIE;
$request->file = $_FILES ?? [];
return $request;
}
@ -1126,7 +1126,7 @@ class Request
if (!empty($files)) {
if (strpos($name, '.')) {
list($name, $sub) = explode('.', $name);
[$name, $sub] = explode('.', $name);
}
// 处理上传文件
@ -1244,7 +1244,7 @@ class Request
if ('' != $name) {
// 解析name
if (strpos($name, '/')) {
list($name, $type) = explode('/', $name);
[$name, $type] = explode('/', $name);
}
$data = $this->getData($data, $name);
@ -1794,11 +1794,11 @@ class Request
*/
public function contentType(): string
{
$contentType = $this->server('CONTENT_TYPE');
$contentType = $this->header('Content-Type');
if ($contentType) {
if (strpos($contentType, ';')) {
list($type) = explode(';', $contentType);
[$type] = explode(';', $contentType);
} else {
$type = $contentType;
}
@ -2057,6 +2057,10 @@ class Request
public function withInput(string $input)
{
$this->input = $input;
if (!empty($input)) {
$this->post = $this->getInputData($input);
$this->put = $this->getInputData($input);
}
return $this;
}

View File

@ -138,8 +138,9 @@ abstract class Response
header($name . (!is_null($val) ? ':' . $val : ''));
}
}
$this->cookie->save();
if ($this->cookie) {
$this->cookie->save();
}
$this->sendData($data);

View File

@ -156,7 +156,7 @@ class Validate
/**
* 验证失败错误信息
* @var array
* @var string|array
*/
protected $error = [];
@ -491,7 +491,7 @@ class Validate
// field => 'rule1|rule2...' field => ['rule1','rule2',...]
if (strpos($key, '|')) {
// 字段|描述 用于指定属性名称
list($key, $title) = explode('|', $key);
[$key, $title] = explode('|', $key);
} else {
$title = $this->field[$key] ?? $key;
}
@ -560,7 +560,7 @@ class Validate
$result = call_user_func_array($rule, [$value]);
} else {
// 判断验证类型
list($type, $rule) = $this->getValidateType($key, $rule);
[$type, $rule] = $this->getValidateType($key, $rule);
$callback = $this->type[$type] ?? [$this, $type];
@ -614,7 +614,7 @@ class Validate
$info = is_numeric($key) ? '' : $key;
} else {
// 判断验证类型
list($type, $rule, $info) = $this->getValidateType($key, $rule);
[$type, $rule, $info] = $this->getValidateType($key, $rule);
if (isset($this->append[$field]) && in_array($info, $this->append[$field])) {
@ -682,7 +682,7 @@ class Validate
}
if (strpos($rule, ':')) {
list($type, $rule) = explode(':', $rule, 2);
[$type, $rule] = explode(':', $rule, 2);
if (isset($this->alias[$type])) {
// 判断别名
$type = $this->alias[$type];
@ -1072,13 +1072,13 @@ class Validate
if ($rule) {
$rule = explode(',', $rule);
list($width, $height, $type) = getimagesize($file->getRealPath());
[$width, $height, $type] = getimagesize($file->getRealPath());
if (isset($rule[2])) {
$imageType = strtolower($rule[2]);
if ('jpeg' == $imageType) {
$imageType = 'jpg';
if ('jpg' == $imageType) {
$imageType = 'jpeg';
}
if (image_type_to_extension($type, false) != $imageType) {
@ -1086,7 +1086,7 @@ class Validate
}
}
list($w, $h) = $rule;
[$w, $h] = $rule;
return $w == $width && $h == $height;
}
@ -1173,7 +1173,7 @@ class Validate
public function filter($value, $rule): bool
{
if (is_string($rule) && strpos($rule, ',')) {
list($rule, $param) = explode(',', $rule);
[$rule, $param] = explode(',', $rule);
} elseif (is_array($rule)) {
$param = $rule[1] ?? null;
$rule = $rule[0];
@ -1194,7 +1194,7 @@ class Validate
*/
public function requireIf($value, $rule, array $data = []): bool
{
list($field, $val) = explode(',', $rule);
[$field, $val] = explode(',', $rule);
if ($this->getDataValue($data, $field) == $val) {
return !empty($value) || '0' == $value;
@ -1296,7 +1296,7 @@ class Validate
if (is_string($rule)) {
$rule = explode(',', $rule);
}
list($min, $max) = $rule;
[$min, $max] = $rule;
return $value >= $min && $value <= $max;
}
@ -1313,7 +1313,7 @@ class Validate
if (is_string($rule)) {
$rule = explode(',', $rule);
}
list($min, $max) = $rule;
[$min, $max] = $rule;
return $value < $min || $value > $max;
}
@ -1337,7 +1337,7 @@ class Validate
if (is_string($rule) && strpos($rule, ',')) {
// 长度区间
list($min, $max) = explode(',', $rule);
[$min, $max] = explode(',', $rule);
return $length >= $min && $length <= $max;
}
@ -1452,7 +1452,7 @@ class Validate
$rule = explode(',', $rule);
}
list($start, $end) = $rule;
[$start, $end] = $rule;
if (!is_numeric($start)) {
$start = strtotime($start);
@ -1512,7 +1512,10 @@ class Validate
return is_scalar($value) && 1 === preg_match($rule, (string) $value);
}
// 获取错误信息
/**
* 获取错误信息
* @return array|string
*/
public function getError()
{
return $this->error;

View File

@ -18,6 +18,7 @@ use DateTime;
use DateTimeInterface;
use Exception;
use Psr\SimpleCache\CacheInterface;
use think\Container;
use think\contract\CacheHandlerInterface;
use think\exception\InvalidArgumentException;
use throwable;
@ -156,7 +157,7 @@ abstract class Driver implements CacheInterface, CacheHandlerInterface
if ($value instanceof Closure) {
// 获取缓存数据
$value = $value();
$value = Container::getInstance()->invokeFunction($value);
}
// 缓存数据
@ -227,7 +228,7 @@ abstract class Driver implements CacheInterface, CacheHandlerInterface
return (string) $data;
}
$serialize = $this->options['serialize'][0] ?? "\Opis\Closure\serialize";
$serialize = $this->options['serialize'][0] ?? "serialize";
return $serialize($data);
}
@ -244,7 +245,7 @@ abstract class Driver implements CacheInterface, CacheHandlerInterface
return $data;
}
$unserialize = $this->options['serialize'][1] ?? "\Opis\Closure\unserialize";
$unserialize = $this->options['serialize'][1] ?? "unserialize";
return $unserialize($data);
}

View File

@ -64,7 +64,7 @@ class Memcache extends Driver
foreach ($hosts as $i => $host) {
$port = $ports[$i] ?? $ports[0];
$this->options['timeout'] > 0 ?
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1, $this->options['timeout']) :
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1, (int) $this->options['timeout']) :
$this->handler->addServer($host, (int) $port, $this->options['persistent'], 1);
}
}

View File

@ -181,15 +181,18 @@ class Memcached extends Driver
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @param bool|false $ttl
* @return bool
*/
public function delete($name): bool
public function delete($name, $ttl = false): bool
{
$this->writeTimes++;
$key = $this->getCacheKey($name);
return $this->handler->delete($key);
return false === $ttl ?
$this->handler->delete($key) :
$this->handler->delete($key, $ttl);
}
/**

View File

@ -58,9 +58,9 @@ class Redis extends Driver
$this->handler = new \Redis;
if ($this->options['persistent']) {
$this->handler->pconnect($this->options['host'], (int) $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
$this->handler->pconnect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout'], 'persistent_id_' . $this->options['select']);
} else {
$this->handler->connect($this->options['host'], (int) $this->options['port'], $this->options['timeout']);
$this->handler->connect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout']);
}
if ('' != $this->options['password']) {
@ -115,7 +115,7 @@ class Redis extends Driver
$value = $this->handler->get($this->getCacheKey($name));
if (false === $value) {
if (false === $value || is_null($value)) {
return $default;
}

View File

@ -79,7 +79,7 @@ abstract class Make extends Command
}
if (strpos($name, '@')) {
list($app, $name) = explode('@', $name);
[$app, $name] = explode('@', $name);
} else {
$app = '';
}

View File

@ -46,7 +46,7 @@ class Route extends Command
$this->app->route->lazy(false);
// 路由检测
$path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
$path = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'route' . DIRECTORY_SEPARATOR ;
$files = is_dir($path) ? scandir($path) : [];

View File

@ -75,7 +75,9 @@ class Handle
$log .= PHP_EOL . $exception->getTraceAsString();
}
$this->app->log->record($log, 'error');
try {
$this->app->log->record($log, 'error');
} catch (Exception $e){}
}
}
@ -150,14 +152,23 @@ class Handle
{
if ($this->app->isDebug()) {
// 调试模式,获取详细的错误信息
$traces = [];
$nextException = $exception;
do {
$traces[] = [
'name' => get_class($nextException),
'file' => $nextException->getFile(),
'line' => $nextException->getLine(),
'code' => $this->getCode($nextException),
'message' => $this->getMessage($nextException),
'trace' => $nextException->getTrace(),
'source' => $this->getSourceCode($nextException),
];
} while ($nextException = $nextException->getPrevious());
$data = [
'name' => get_class($exception),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $this->getMessage($exception),
'trace' => $exception->getTrace(),
'code' => $this->getCode($exception),
'source' => $this->getSourceCode($exception),
'message' => $this->getMessage($exception),
'traces' => $traces,
'datas' => $this->getExtendData($exception),
'tables' => [
'GET Data' => $this->app->request->get(),

View File

@ -12,6 +12,8 @@ declare (strict_types = 1);
namespace think\log\driver;
use Psr\Container\NotFoundExceptionInterface;
use think\App;
use think\contract\LogHandlerInterface;
/**
@ -20,11 +22,13 @@ use think\contract\LogHandlerInterface;
*/
class Socket implements LogHandlerInterface
{
public $port = 1116; //SocketLog 服务的http的端口号
protected $app;
protected $config = [
// socket服务器地址
'host' => 'localhost',
// socket服务器端口
'port' => 1116,
// 是否显示加载的文件列表
'show_included_files' => false,
// 日志强制记录到配置的client_id
@ -33,6 +37,10 @@ class Socket implements LogHandlerInterface
'allow_client_ids' => [],
// 调试开关
'debug' => false,
// 输出到浏览器时默认展开的日志级别
'expand_level' => ['debug'],
// 日志头渲染回调
'format_head' => null,
];
protected $css = [
@ -45,16 +53,25 @@ class Socket implements LogHandlerInterface
protected $allowForceClientIds = []; //配置强制推送且被授权的client_id
protected $clientArg = [];
/**
* 架构函数
* @access public
* @param App $app
* @param array $config 缓存参数
*/
public function __construct(array $config = [])
public function __construct(App $app, array $config = [])
{
$this->app = $app;
if (!empty($config)) {
$this->config = array_merge($this->config, $config);
}
if (!isset($config['debug'])) {
$this->config['debug'] = $app->isDebug();
}
}
/**
@ -72,11 +89,18 @@ class Socket implements LogHandlerInterface
$trace = [];
if ($this->config['debug']) {
if (isset($_SERVER['HTTP_HOST'])) {
$current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
if ($this->app->exists('request')) {
$current_uri = $this->app->request->url(true);
} else {
$current_uri = 'cmd:' . implode(' ', $_SERVER['argv']);
$current_uri = 'cmd:' . implode(' ', $_SERVER['argv'] ?? []);
}
if (!empty($this->config['format_head'])) {
try {
$current_uri = $this->app->invoke($this->config['format_head'], [$current_uri]);
} catch (NotFoundExceptionInterface $notFoundException) {
// Ignore exception
}
}
// 基本信息
@ -87,11 +111,13 @@ class Socket implements LogHandlerInterface
];
}
$expand_level = array_flip($this->config['expand_level']);
foreach ($log as $type => $val) {
$trace[] = [
'type' => 'groupCollapsed',
'type' => isset($expand_level[$type]) ? 'group' : 'groupCollapsed',
'msg' => '[ ' . $type . ' ]',
'css' => isset($this->css[$type]) ? $this->css[$type] : '',
'css' => $this->css[$type] ?? '',
];
foreach ($val as $msg) {
@ -160,11 +186,11 @@ class Socket implements LogHandlerInterface
/**
* 发送给指定客户端
* @access protected
* @author Zjmainstay
* @param $tabid
* @param $client_id
* @param $logs
* @param $force_client_id
* @author Zjmainstay
*/
protected function sendToClient($tabid, $client_id, $logs, $force_client_id)
{
@ -175,12 +201,17 @@ class Socket implements LogHandlerInterface
'force_client_id' => $force_client_id,
];
$msg = @json_encode($logs);
$msg = json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR);
$address = '/' . $client_id; //将client_id作为地址 server端通过地址判断将日志发布给谁
$this->send($this->config['host'], $msg, $address);
$this->send($this->config['host'], $this->config['port'], $msg, $address);
}
/**
* 检测客户授权
* @access protected
* @return bool
*/
protected function check()
{
$tabid = $this->getClientArg('tabid');
@ -211,45 +242,50 @@ class Socket implements LogHandlerInterface
return true;
}
protected function getClientArg($name)
/**
* 获取客户参数
* @access protected
* @param string $name
* @return string
*/
protected function getClientArg(string $name)
{
static $args = [];
$key = 'HTTP_USER_AGENT';
if (isset($_SERVER['HTTP_SOCKETLOG'])) {
$key = 'HTTP_SOCKETLOG';
if (!$this->app->exists('request')) {
return '';
}
if (!isset($_SERVER[$key])) {
return;
}
if (empty($args)) {
if (!preg_match('/SocketLog\((.*?)\)/', $_SERVER[$key], $match)) {
$args = ['tabid' => null];
return;
if (empty($this->clientArg)) {
if (empty($socketLog = $this->app->request->header('socketlog'))) {
if (empty($socketLog = $this->app->request->header('User-Agent'))) {
return '';
}
}
parse_str($match[1], $args);
if (!preg_match('/SocketLog\((.*?)\)/', $socketLog, $match)) {
$this->clientArg = ['tabid' => null, 'client_id' => null];
return '';
}
parse_str($match[1] ?? '', $this->clientArg);
}
if (isset($args[$name])) {
return $args[$name];
if (isset($this->clientArg[$name])) {
return $this->clientArg[$name];
}
return;
return '';
}
/**
* @access protected
* @param string $host - $host of socket server
* @param int $port - $port of socket server
* @param string $message - 发送的消息
* @param string $address - 地址
* @return bool
*/
protected function send($host, $message = '', $address = '/')
protected function send($host, $port, $message = '', $address = '/')
{
$url = 'http://' . $host . ':' . $this->port . $address;
$url = 'http://' . $host . ':' . $port . $address;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
@ -267,5 +303,4 @@ class Socket implements LogHandlerInterface
return curl_exec($ch);
}
}

View File

@ -65,7 +65,7 @@ class CheckRequestCache
if ($cache) {
if (is_array($cache)) {
list($key, $expire, $tag) = $cache;
[$key, $expire, $tag] = $cache;
} else {
$key = str_replace('|', '/', $request->url());
$expire = $cache;
@ -76,8 +76,8 @@ class CheckRequestCache
// 读取缓存
return Response::create()->code(304);
} elseif (($hit = $this->cache->get($key)) !== null) {
list($content, $header, $when) = $hit;
if ($expire === null || $when + $expire > $request->server('REQUEST_TIME')) {
[$content, $header, $when] = $hit;
if (null === $expire || $when + $expire > $request->server('REQUEST_TIME')) {
return Response::create($content)->header($header);
}
}
@ -130,7 +130,7 @@ class CheckRequestCache
// 自动缓存功能
$key = '__URL__';
} elseif (strpos($key, '|')) {
list($key, $fun) = explode('|', $key);
[$key, $fun] = explode('|', $key);
}
// 特殊规则替换

View File

@ -139,16 +139,16 @@ abstract class Dispatch
$this->createBindModel($option['model'], $this->param);
}
// 数据自动验证
if (isset($option['validate'])) {
$this->autoValidate($option['validate']);
}
// 记录当前请求的路由规则
$this->request->setRule($this->rule);
// 记录路由变量
$this->request->setRoute($this->param);
// 数据自动验证
if (isset($option['validate'])) {
$this->autoValidate($option['validate']);
}
}
/**
@ -167,7 +167,7 @@ abstract class Dispatch
$fields = explode('&', $key);
if (is_array($val)) {
list($model, $exception) = $val;
[$model, $exception] = $val;
} else {
$model = $val;
$exception = true;
@ -206,7 +206,7 @@ abstract class Dispatch
*/
protected function autoValidate(array $option): void
{
list($validate, $scene, $message, $batch) = $option;
[$validate, $scene, $message, $batch] = $option;
if (is_array($validate)) {
// 指定验证规则

View File

@ -110,7 +110,7 @@ class Domain extends RuleGroup
protected function parseBindAppendParam(string &$bind): void
{
if (false !== strpos($bind, '?')) {
list($bind, $query) = explode('?', $bind);
[$bind, $query] = explode('?', $bind);
parse_str($query, $vars);
$this->append($vars);
}

View File

@ -355,7 +355,7 @@ class RuleGroup extends Rule
$var = [];
foreach ($match as $key => $val) {
if (is_string($key) && '' !== $val) {
list($name, $pos) = explode('_THINK_', $key);
[$name, $pos] = explode('_THINK_', $key);
$var[$name] = $val;
}

View File

@ -213,7 +213,7 @@ class Url
if ($suffix) {
$suffix = true === $suffix ? $this->route->config('url_html_suffix') : $suffix;
if ($pos = strpos($suffix, '|')) {
if (is_string($suffix) && $pos = strpos($suffix, '|')) {
$suffix = substr($suffix, 0, $pos);
}
}
@ -324,11 +324,12 @@ class Url
}
$type = $this->route->config('url_common_param');
$keys = [];
foreach ($pattern as $key => $val) {
if (isset($vars[$key])) {
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? $vars[$key] : urlencode((string) $vars[$key]), $url);
unset($vars[$key]);
$url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? $vars[$key] : urlencode((string) $vars[$key]), $url);
$keys[] = $key;
$url = str_replace(['/?', '-?'], ['/', '-'], $url);
$result = [rtrim($url, '?/-'), $domain, $suffix];
} elseif (2 == $val) {
@ -336,10 +337,14 @@ class Url
$url = str_replace(['/?', '-?'], ['/', '-'], $url);
$result = [rtrim($url, '?/-'), $domain, $suffix];
} else {
$result = null;
$keys = [];
break;
}
}
$vars = array_diff_key($vars, array_flip($keys));
if (isset($result)) {
return $result;
}
@ -373,16 +378,16 @@ class Url
if (false !== strpos($anchor, '?')) {
// 解析参数
list($anchor, $info['query']) = explode('?', $anchor, 2);
[$anchor, $info['query']] = explode('?', $anchor, 2);
}
if (false !== strpos($anchor, '@')) {
// 解析域名
list($anchor, $domain) = explode('@', $anchor, 2);
[$anchor, $domain] = explode('@', $anchor, 2);
}
} elseif (strpos($url, '@') && false === strpos($url, '\\')) {
// 解析域名
list($url, $domain) = explode('@', $url, 2);
[$url, $domain] = explode('@', $url, 2);
}
}

View File

@ -58,7 +58,7 @@ class Url extends Controller
// 解析控制器
$controller = !empty($path) ? array_shift($path) : null;
if ($controller && !preg_match('/^[A-Za-z][\w|\.]*$/', $controller)) {
if ($controller && !preg_match('/^[A-Za-z0-9][\w|\.]*$/', $controller)) {
throw new HttpException(404, 'controller not exists:' . $controller);
}
@ -100,7 +100,7 @@ class Url extends Controller
*/
protected function hasDefinedRoute(array $route): bool
{
list($controller, $action) = $route;
[$controller, $action] = $route;
// 检查地址是否被定义过路由
$name = strtolower(Str::studly($controller) . '/' . $action);

View File

@ -152,7 +152,7 @@ class File implements SessionHandlerInterface
if ($this->config['data_compress'] && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
$content = (string) gzuncompress($content);
}
return $content;

View File

@ -83,10 +83,6 @@ class Php implements TemplateHandlerInterface
$this->template = $template;
// 记录视图信息
$this->app->log
->record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]');
extract($data, EXTR_OVERWRITE);
include $this->template;
@ -119,8 +115,8 @@ class Php implements TemplateHandlerInterface
// 获取视图根目录
if (strpos($template, '@')) {
// 跨模块调用
list($app, $template) = explode('@', $template);
// 跨应用调用
[$app, $template] = explode('@', $template);
}
if ($this->config['view_path'] && !isset($app)) {

View File

@ -1,79 +1,93 @@
<?php
if(!function_exists('parse_padding')){
function parse_padding($source)
{
$length = strlen(strval(count($source['source']) + $source['first']));
return 40 + ($length - 1) * 8;
}
/** @var array $traces */
if (!function_exists('parse_padding')) {
function parse_padding($source)
{
$length = strlen(strval(count($source['source']) + $source['first']));
return 40 + ($length - 1) * 8;
}
}
if(!function_exists('parse_class')){
function parse_class($name)
{
$names = explode('\\', $name);
return '<abbr title="'.$name.'">'.end($names).'</abbr>';
}
if (!function_exists('parse_class')) {
function parse_class($name)
{
$names = explode('\\', $name);
return '<abbr title="'.$name.'">'.end($names).'</abbr>';
}
}
if(!function_exists('parse_file')){
function parse_file($file, $line)
{
return '<a class="toggle" title="'."{$file} line {$line}".'">'.basename($file)." line {$line}".'</a>';
}
if (!function_exists('parse_file')) {
function parse_file($file, $line)
{
return '<a class="toggle" title="'."{$file} line {$line}".'">'.basename($file)." line {$line}".'</a>';
}
}
if(!function_exists('parse_args')){
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if(count($item) > 3){
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if(strlen($item) > 20){
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
if (!function_exists('parse_args')) {
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
return implode(', ', $result);
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
}
return implode(', ', $result);
}
}
if (!function_exists('echo_value')) {
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
}
?>
<!DOCTYPE html>
<html>
@ -123,11 +137,9 @@
.line-error{
background: #f8cbcb;
}
.echo table {
width: 100%;
}
.echo pre {
padding: 16px;
overflow: auto;
@ -138,12 +150,10 @@
border-radius: 3px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.echo pre > pre {
padding: 0;
margin: 0;
}
/* Exception Info */
.exception {
margin-top: 20px;
@ -156,9 +166,8 @@
font-size:16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑";
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
}
.exception .code{
float: left;
text-align: center;
@ -185,8 +194,8 @@
display: inline-block;
min-width: 100%;
box-sizing: border-box;
font-size:14px;
font-family: "Century Gothic",Consolas,"Liberation Mono",Courier,Verdana;
font-size:14px;
font-family: "Century Gothic",Consolas,"Liberation Mono",Courier,Verdana,serif;
padding-left: <?php echo (isset($source) && !empty($source)) ? parse_padding($source) : 40; ?>px;
}
.exception .source-code pre li{
@ -199,16 +208,20 @@
height: 100%;
display: inline-block;
border-left: 1px solid #fff;
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑";
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
}
.exception .trace{
padding: 6px;
border: 1px solid #ddd;
border-top: 0 none;
line-height: 16px;
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑";
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
}
.exception .trace h2:hover {
text-decoration: underline;
cursor: pointer;
}
.exception .trace ol{
margin: 12px;
@ -227,7 +240,7 @@
margin: 12px 0;
box-sizing: border-box;
table-layout:fixed;
word-wrap:break-word;
word-wrap:break-word;
}
.exception-var table caption{
text-align: left;
@ -243,7 +256,7 @@
}
.exception-var table tbody{
font-size: 13px;
font-family: Consolas,"Liberation Mono",Courier,"微软雅黑";
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑",serif;
}
.exception-var table td{
padding: 0 6px;
@ -283,65 +296,63 @@
</style>
</head>
<body>
<?php if(\think\facade\App::isDebug()) { ?>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="message">
<div class="info">
<div>
<h2>[<?php echo $code; ?>]&nbsp;<?php echo sprintf('%s in %s', parse_class($name), parse_file($file, $line)); ?></h2>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div><h1><?php echo nl2br(htmlentities($message)); ?></h1></div>
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
</div>
</div>
<?php if(!empty($source)){?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol start="<?php echo $source['first']; ?>"><?php foreach ((array) $source['source'] as $key => $value) { ?><li class="line-<?php echo $key + $source['first']; ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php }?>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol start="<?php echo $trace['source']['first']; ?>"><?php foreach ((array) $trace['source']['source'] as $key => $value) { ?><li class="line-<?php echo "{$index}-"; echo $key + $trace['source']['first']; echo $trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''; ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php }?>
<div class="trace">
<h2>Call Stack</h2>
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($file, $line)); ?></li>
<?php foreach ((array) $trace as $value) { ?>
<li>
<?php
// Show Function
if($value['function']){
echo sprintf(
'at %s%s%s(%s)',
isset($value['class']) ? parse_class($value['class']) : '',
isset($value['type']) ? $value['type'] : '',
$value['function'],
isset($value['args'])?parse_args($value['args']):''
);
}
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array) $trace['trace'] as $value) { ?>
<li>
<?php
// Show Function
if ($value['function']) {
echo sprintf(
'at %s%s%s(%s)',
isset($value['class']) ? parse_class($value['class']) : '',
isset($value['type']) ? $value['type'] : '',
$value['function'],
isset($value['args'])?parse_args($value['args']):''
);
}
// Show line
if (isset($value['file']) && isset($value['line'])) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
// Show line
if (isset($value['file']) && isset($value['line'])) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
<?php } ?>
</ol>
</div>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
</div>
<?php } ?>
<?php if(!empty($datas)){ ?>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array) $datas as $label => $value) { ?>
<table>
<?php if(empty($value)){ ?>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
@ -349,19 +360,7 @@
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td>
<?php
if(is_array($val) || is_object($val)){
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} else if(is_bool($val)) {
echo $val ? 'true' : 'false';
} else if(is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
?>
</td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
@ -371,12 +370,12 @@
</div>
<?php } ?>
<?php if(!empty($tables)){ ?>
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array) $tables as $label => $value) { ?>
<table>
<?php if(empty($value)){ ?>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
@ -384,19 +383,7 @@
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td>
<?php
if(is_array($val) || is_object($val)){
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} else if(is_bool($val)) {
echo $val ? 'true' : 'false';
} else if(is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
?>
</td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
@ -410,12 +397,10 @@
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V<?php echo \think\facade\App::version(); ?></span>
<span>{ -API开发设计的高性能框架 }</span>
<span>- <a title="官方手册" href="https://www.kancloud.cn/manual/thinkphp6_0/">官方手册</a></span>
<span>- <a title="官方手册" href="https://www.kancloud.cn/manual/thinkphp6_0/content">官方手册</a></span>
</div>
<?php if(\think\facade\App::isDebug()) { ?>
<?php if (\think\facade\App::isDebug()) { ?>
<script>
var LINE = <?php echo $line; ?>;
function $(selector, node){
var elements;
@ -483,21 +468,33 @@
}
}
// 设置出错行
var err_line = $('.line-' + LINE, ol[0])[0];
err_line.className = err_line.className + ' line-error';
(function () {
var expand = function (dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i ++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function () {
expand(this);
};
}
})();
$.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function(){
prettyPrint();
// 解决Firefox浏览器一个很诡异的问题
// 当代码高亮后ol的行号莫名其妙的错位
// 但是只要刷新li里面的html重新渲染就没有问题了
if(window.navigator.userAgent.indexOf('Firefox') >= 0){
ol[0].innerHTML = ol[0].innerHTML;
}
});
})();
</script>
<?php } ?>

View File

@ -121,11 +121,11 @@ class CacheTest extends TestCase
$redis->shouldReceive("decrby")->once()->with('foo', 2)->andReturnTrue();
$redis->shouldReceive("get")->once()->with('foo')->andReturn(6);
$redis->shouldReceive("get")->once()->with('foo')->andReturn(4);
$redis->shouldReceive("set")->once()->with('bar', \Opis\Closure\serialize(true))->andReturnTrue();
$redis->shouldReceive("set")->once()->with('baz', \Opis\Closure\serialize(null))->andReturnTrue();
$redis->shouldReceive("set")->once()->with('bar', serialize(true))->andReturnTrue();
$redis->shouldReceive("set")->once()->with('baz', serialize(null))->andReturnTrue();
$redis->shouldReceive("del")->once()->with('baz')->andReturnTrue();
$redis->shouldReceive("flushDB")->once()->andReturnTrue();
$redis->shouldReceive("set")->once()->with('bar', \Opis\Closure\serialize('foobar'))->andReturnTrue();
$redis->shouldReceive("set")->once()->with('bar', serialize('foobar'))->andReturnTrue();
$redis->shouldReceive("sAdd")->once()->with('tag:' . md5('foo'), 'bar')->andReturnTrue();
$redis->shouldReceive("sMembers")->once()->with('tag:' . md5('foo'))->andReturn(['bar']);
$redis->shouldReceive("del")->once()->with(['bar'])->andReturnTrue();

View File

@ -245,11 +245,22 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
*/
public function newInstance(array $data = [], $where = null): Model
{
if (empty($data)) {
return new static();
$model = new static($data);
if ($this->connection) {
$model->setConnection($this->connection);
}
$model = (new static($data))->exists(true);
if ($this->suffix) {
$model->setSuffix($this->suffix);
}
if (empty($data)) {
return $model;
}
$model->exists(true);
$model->setUpdateWhere($where);
$model->trigger('AfterRead');
@ -268,6 +279,28 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$this->updateWhere = $where;
}
/**
* 设置当前模型的数据库连接
* @access public
* @param string $connection 数据表连接标识
* @return $this
*/
public function setConnection(string $connection)
{
$this->connection = $connection;
return $this;
}
/**
* 获取当前模型的数据库连接标识
* @access public
* @return string
*/
public function getConnection(): string
{
return $this->connection ?: '';
}
/**
* 设置当前模型数据表的后缀
* @access public
@ -686,13 +719,13 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
{
$pk = $this->getPk();
if (is_string($pk) && isset($this->data[$pk])) {
$where = [[$pk, '=', $this->data[$pk]]];
$this->key = $this->data[$pk];
if (is_string($pk) && isset($this->origin[$pk])) {
$where = [[$pk, '=', $this->origin[$pk]]];
$this->key = $this->origin[$pk];
} elseif (is_array($pk)) {
foreach ($pk as $field) {
if (isset($this->data[$field])) {
$where[] = [$field, '=', $this->data[$field]];
if (isset($this->origin[$field])) {
$where[] = [$field, '=', $this->origin[$field]];
}
}
}
@ -964,6 +997,20 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
return $model;
}
/**
* 切换数据库连接进行查询
* @access public
* @param string $connection 数据库连接标识
* @return Model
*/
public static function connect(string $connection)
{
$model = new static();
$model->setConnection($connection);
return $model;
}
public function __call($method, $args)
{
if ('withattr' == strtolower($method)) {

View File

@ -1118,10 +1118,10 @@ abstract class PDOConnection extends Connection implements ConnectionInterface
if (!empty($options['cache'])) {
// 判断查询缓存
$cacheItem = $this->parseCache($query, $options['cache']);
$key = $cacheItem->getKey();
$name = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
if ($this->cache->has($name)) {
return $this->cache->get($name);
}
}
@ -1144,8 +1144,9 @@ abstract class PDOConnection extends Connection implements ConnectionInterface
} elseif (('*' == $column || strpos($column, ',')) && $key) {
$result = array_column($resultSet, null, $key);
} else {
$fields = array_keys($resultSet[0]);
$key = $key ?: array_shift($fields);
if (empty($key)) {
$key = null;
}
if (strpos($column, ',')) {
$column = null;
@ -1153,7 +1154,7 @@ abstract class PDOConnection extends Connection implements ConnectionInterface
[$alias, $column] = explode('.', $column);
}
if (strpos($key, '.')) {
if (is_string($key) && strpos($key, '.')) {
[$alias, $key] = explode('.', $key);
}

View File

@ -353,12 +353,14 @@ class Query extends BaseQuery
/**
* 获取当前数据表的自增主键
* @access public
* @return string
* @return string|null
*/
public function getAutoInc()
{
if (empty($this->autoinc)) {
$this->autoinc = $this->connection->getAutoInc($this->getTable());
$tableName = $this->getTable();
if (empty($this->autoinc) && $tableName) {
$this->autoinc = $this->connection->getAutoInc($tableName);
}
return $this->autoinc;

View File

@ -120,7 +120,7 @@ class Mysql extends PDOConnection
public function startTransXa(string $xid)
{
$this->initConnect(true);
$this->linkID->execute("XA START '$xid'");
$this->linkID->exec("XA START '$xid'");
}
/**
@ -132,8 +132,8 @@ class Mysql extends PDOConnection
public function prepareXa(string $xid)
{
$this->initConnect(true);
$this->linkID->execute("XA END '$xid'");
$this->linkID->execute("XA PREPARE '$xid'");
$this->linkID->exec("XA END '$xid'");
$this->linkID->exec("XA PREPARE '$xid'");
}
/**
@ -145,7 +145,7 @@ class Mysql extends PDOConnection
public function commitXa(string $xid)
{
$this->initConnect(true);
$this->linkID->execute("XA COMMIT '$xid'");
$this->linkID->exec("XA COMMIT '$xid'");
}
/**
@ -157,6 +157,6 @@ class Mysql extends PDOConnection
public function rollbackXa(string $xid)
{
$this->initConnect(true);
$this->linkID->execute("XA ROLLBACK '$xid'");
$this->linkID->exec("XA ROLLBACK '$xid'");
}
}

View File

@ -24,16 +24,16 @@ use think\admin\Service;
* @package app\store\service
* =================================
*
* CREATE TABLE `SystemMessageHistory` (
* CREATE TABLE `system_message_history` (
* `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
* `region` varchar(255) DEFAULT '0' COMMENT '国家编号',
* `phone` varchar(100) DEFAULT '' COMMENT '目标手机',
* `content` varchar(512) DEFAULT '' COMMENT '短信内容',
* `region` varchar(100) DEFAULT '' COMMENT '国家编号',
* `result` varchar(100) DEFAULT '' COMMENT '返回结果',
* `content` varchar(512) DEFAULT '' COMMENT '短信内容',
* `create_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
* PRIMARY KEY (`id`) USING BTREE,
* KEY `idx_system_message_history_phone` (`phone`) USING BTREE,
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='短信-记录';
* KEY `idx_system_message_history_phone` (`phone`) USING BTREE
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统-短信';
*
* =================================
* 发送国内短信需要给产品码 [productid]
@ -154,7 +154,6 @@ class MessageService extends Service
/**
* 发送国内短信验证码
* @param string $mid 会员ID
* @param string $phone 目标手机
* @param integer $wait 等待时间
* @param string $type 短信模板
@ -163,7 +162,7 @@ class MessageService extends Service
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sendChinaSmsByCode($mid, $phone, $wait = 120, $type = 'sms_reg_template')
public function sendChinaSmsByCode($phone, $wait = 120, $type = 'sms_reg_template')
{
$cache = $this->app->cache->get($ckey = "{$type}_{$phone}", []);
if (is_array($cache) && isset($cache['time']) && $cache['time'] > time() - $wait) {
@ -175,7 +174,7 @@ class MessageService extends Service
$content = '您的验证码为{code},请在十分钟内完成操作!';
}
$this->app->cache->set($ckey, $cache = ['code' => $code, 'time' => time()], 600);
if ($this->sendChinaSms($mid, $phone, str_replace('{code}', $code, $content))) {
if ($this->sendChinaSms($phone, str_replace('{code}', $code, $content))) {
$dtime = ($cache['time'] + $wait < time()) ? 0 : ($wait - time() + $cache['time']);
return [1, '短信验证码发送成功!', ['time' => $dtime]];
} else {
@ -190,7 +189,7 @@ class MessageService extends Service
* @param string $type 短信模板
* @return boolean
*/
public function checkChinaSmsByCode($phone, $code, $type = 'sms_reg_template')
public function check($phone, $code, $type = 'sms_reg_template')
{
$cache = $this->app->cache->get($cachekey = "{$type}_{$phone}", []);
return is_array($cache) && isset($cache['code']) && $cache['code'] == $code;
@ -236,7 +235,6 @@ class MessageService extends Service
/**
* 发送国际短信内容
* @param string $mid 会员编号
* @param string $code 国家代码
* @param string $mobile 手机号码
* @param string $content 发送内容
@ -245,7 +243,7 @@ class MessageService extends Service
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sendGlobeSms($mid, $code, $mobile, $content)
public function sendGlobeSms($code, $mobile, $content)
{
$tkey = date("YmdHis");
$result = HttpExtend::post('http://intl.zthysms.com/intSendSms.do', [
@ -254,7 +252,7 @@ class MessageService extends Service
'password' => md5(md5(sysconf('sms_zt_password2')) . $tkey),
]);
$this->app->db->name($this->table)->insert([
'mid' => $mid, 'region' => $code, 'phone' => $mobile, 'content' => $content, 'result' => $result,
'region' => $code, 'phone' => $mobile, 'content' => $content, 'result' => $result,
]);
return intval($result) === 1;
}