diff --git a/core/convention.php b/core/convention.php index 1dcf80dc..d9003ca6 100644 --- a/core/convention.php +++ b/core/convention.php @@ -18,7 +18,7 @@ return [ // 注册的根命名空间 'root_namespace' => [], // 扩展配置文件 - 'extra_config_list' => ['database', 'route', 'validate'], + 'extra_config_list' => ['database', 'validate'], // 扩展函数文件 'extra_file_list' => [THINK_PATH . 'helper' . EXT], // 默认输出类型 diff --git a/core/library/think/App.php b/core/library/think/App.php index 6daf7300..30350e3a 100644 --- a/core/library/think/App.php +++ b/core/library/think/App.php @@ -65,6 +65,7 @@ class App protected static $routeMust; protected static $dispatch; + protected static $file = []; /** * 执行应用程序 @@ -388,8 +389,9 @@ class App if (!empty($config['extra_file_list'])) { foreach ($config['extra_file_list'] as $file) { $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT; - if (is_file($file)) { - include_once $file; + if (is_file($file) && !isset(self::$file[$file])) { + include $file; + self::$file[$file] = true; } } } @@ -479,9 +481,12 @@ class App $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on']; if ($check) { // 开启路由 - if (!empty($config['route'])) { + if (is_file(RUNTIME_PATH . 'route.php')) { + // 读取路由缓存 + Route::rules(include RUNTIME_PATH . 'route.php' ?: []); + } elseif (is_file(CONF_PATH . 'route' . CONF_EXT)) { // 导入路由配置 - Route::import($config['route']); + Route::import(include CONF_PATH . 'route' . CONF_EXT ?: []); } // 路由检测(根据路由定义返回不同的URL调度) $result = Route::check($request, $path, $depr, $config['url_domain_deploy']); diff --git a/core/library/think/Route.php b/core/library/think/Route.php index 24f6fb08..966e569e 100644 --- a/core/library/think/Route.php +++ b/core/library/think/Route.php @@ -65,6 +65,9 @@ class Route // 路由命名标识(用于快速URL生成) private static $name = []; // 当前子域名绑定 + private static $domainBind; + private static $domainRule; + // 当前域名 private static $domain; /** @@ -96,13 +99,32 @@ class Route { if (is_array($domain)) { foreach ($domain as $key => $item) { - self::$rules['domain'][$key] = [$item, $option, $pattern]; + self::domain($key, $item, $option, $pattern); } } else { - self::$rules['domain'][$domain] = [$rule, $option, $pattern]; + if ($rule instanceof \Closure) { + // 执行闭包 + self::setDomain($domain); + call_user_func_array($rule, []); + self::setDomain(null); + } elseif (is_array($rule)) { + self::setDomain($domain); + self::group('', function () use ($rule) { + // 动态注册域名的路由规则 + self::registerRules($rule); + }, $option, $pattern); + self::setDomain(null); + } else { + self::$rules['domain'][$domain]['[bind]'] = [$rule, $option, $pattern]; + } } } + private static function setDomain($domain) + { + self::$domain = $domain; + } + /** * 设置路由绑定 * @access public @@ -211,7 +233,7 @@ class Route public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = []) { $group = self::getGroup('name'); - if (!is_null($group)) { + if (!empty($group)) { // 路由分组 $option = array_merge(self::getGroup('option'), $option); $pattern = array_merge(self::getGroup('pattern'), $pattern); @@ -270,19 +292,34 @@ class Route } $vars = self::parseVar($rule); if (isset($name)) { - self::$name[$name] = [$rule, $vars]; + self::$name[$name] = [$rule, $vars, self::$domain]; } if ($group) { - self::$rules[$type][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + if ('*' != $type) { + $option['method'] = $type; + } + if (self::$domain) { + self::$rules['domain'][self::$domain]['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + } else { + self::$rules['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + } } else { if ('*' != $type && isset(self::$rules['*'][$rule])) { unset(self::$rules['*'][$rule]); } - self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + if (self::$domain) { + self::$rules['domain'][self::$domain][$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + } else { + self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; + } if ('*' == $type) { // 注册路由快捷方式 foreach (['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'] as $method) { - self::$rules[$method][$rule] = true; + if (self::$domain) { + self::$rules['domain'][self::$domain][$method][$rule] = true; + } else { + self::$rules[$method][$rule] = true; + } } } } @@ -299,7 +336,7 @@ class Route if (isset(self::$group[$type])) { return self::$group[$type]; } else { - return null; + return 'name' == $type ? null : []; } } @@ -333,30 +370,33 @@ class Route $option = $name; $name = isset($option['name']) ? $option['name'] : ''; } + // 分组 + $currentGroup = self::getGroup('name'); + if ($currentGroup) { + $name = $currentGroup . ($name ? '/' . ltrim($name, '/') : ''); + } if (!empty($name)) { - // 分组 - $currentGroup = self::getGroup('name'); - if ($currentGroup) { - $name = $currentGroup . '/' . ltrim($name, '/'); - } if ($routes instanceof \Closure) { $currentOption = self::getGroup('option'); $currentPattern = self::getGroup('pattern'); - self::setGroup($name, $option, $pattern); + self::setGroup($name, array_merge($currentOption, $option), array_merge($currentPattern, $pattern)); call_user_func_array($routes, []); self::setGroup($currentGroup, $currentOption, $currentPattern); - self::$rules['*'][$name]['route'] = ''; - self::$rules['*'][$name]['var'] = self::parseVar($name); - self::$rules['*'][$name]['option'] = $option; - self::$rules['*'][$name]['pattern'] = $pattern; + if ($currentGroup != $name) { + self::$rules['*'][$name]['route'] = ''; + self::$rules['*'][$name]['var'] = self::parseVar($name); + self::$rules['*'][$name]['option'] = $option; + self::$rules['*'][$name]['pattern'] = $pattern; + } } else { + $item = []; foreach ($routes as $key => $val) { if (is_numeric($key)) { $key = array_shift($val); } if (is_array($val)) { $route = $val[0]; - $option1 = array_merge($option, $val[1]); + $option1 = array_merge($option, isset($val[1]) ? $val[1] : []); $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []); } else { $route = $val; @@ -375,22 +415,16 @@ class Route } } + } elseif ($routes instanceof \Closure) { + // 闭包注册 + $currentOption = self::getGroup('option'); + $currentPattern = self::getGroup('pattern'); + self::setGroup('', array_merge($currentOption, $option), array_merge($currentPattern, $pattern)); + call_user_func_array($routes, []); + self::setGroup($currentGroup, $currentOption, $currentPattern); } else { - if ($routes instanceof \Closure) { - // 闭包注册 - $currentGroup = self::getGroup('name'); - $currentOption = self::getGroup('option'); - $currentPattern = self::getGroup('pattern'); - if ($currentGroup) { - $name = $currentGroup . '/' . ltrim($name, '/'); - } - self::setGroup($name, $option, $pattern); - call_user_func_array($routes, []); - self::setGroup($currentGroup, $currentOption, $currentPattern); - } else { - // 批量注册路由 - self::rule($routes, '', '*', $option, $pattern); - } + // 批量注册路由 + self::rule($routes, '', '*', $option, $pattern); } } @@ -624,7 +658,7 @@ class Route if (is_array($rules)) { self::$rules = $rules; } elseif ($rules) { - return self::$rules[$rules]; + return true === $rules ? self::$rules : self::$rules[$rules]; } else { $rules = self::$rules; unset($rules['pattern'], $rules['alias'], $rules['domain']); @@ -636,10 +670,11 @@ class Route * 检测子域名部署 * @access public * @param Request $request Request请求对象 + * @param array $currentRules 当前路由规则 * @param string $method 请求类型 * @return void */ - public static function checkDomain($request, $method = 'GET') + public static function checkDomain($request, &$currentRules, $method = 'GET') { // 域名规则 $rules = self::$rules['domain']; @@ -684,55 +719,45 @@ class Route } } if (!empty($item)) { - self::$domain = true; - // 解析子域名部署规则 - list($rule, $option, $pattern) = $item; - if (!empty($option['https']) && !$request->isSsl()) { - // https检测 - throw new HttpException(404, 'must use https request:' . $host); - } - if ($rule instanceof \Closure) { - // 执行闭包 - $reflect = new \ReflectionFunction($rule); - self::$bind = $reflect->invokeArgs([]); - return; - } elseif (is_array($rule)) { - // 清空当前路由规则 - self::$rules[$method] = []; - self::$rules['*'] = []; - self::group('', function () use ($rule) { - // 动态注册域名的路由规则 - self::registerRules($rule); - }, $option, $pattern); - return; - } - - if (strpos($rule, '?')) { - // 传入其它参数 - $array = parse_url($rule); - $result = $array['path']; - parse_str($array['query'], $params); - if (isset($panDomain)) { - $pos = array_search('*', $params); - if (false !== $pos) { - // 泛域名作为参数 - $params[$pos] = $panDomain; - } + if (isset($item['[bind]'])) { + // 解析子域名部署规则 + list($rule, $option, $pattern) = $item['[bind]']; + if (!empty($option['https']) && !$request->isSsl()) { + // https检测 + throw new HttpException(404, 'must use https request:' . $host); } - $_GET = array_merge($_GET, $params); - } else { - $result = $rule; - } - if (0 === strpos($result, '\\')) { - // 绑定到命名空间 例如 \app\index\behavior - self::$bind = ['type' => 'namespace', 'namespace' => $result]; - } elseif (0 === strpos($result, '@')) { - // 绑定到类 例如 @app\index\controller\User - self::$bind = ['type' => 'class', 'class' => substr($result, 1)]; + if (strpos($rule, '?')) { + // 传入其它参数 + $array = parse_url($rule); + $result = $array['path']; + parse_str($array['query'], $params); + if (isset($panDomain)) { + $pos = array_search('*', $params); + if (false !== $pos) { + // 泛域名作为参数 + $params[$pos] = $panDomain; + } + } + $_GET = array_merge($_GET, $params); + } else { + $result = $rule; + } + + if (0 === strpos($result, '\\')) { + // 绑定到命名空间 例如 \app\index\behavior + self::$bind = ['type' => 'namespace', 'namespace' => $result]; + } elseif (0 === strpos($result, '@')) { + // 绑定到类 例如 @app\index\controller\User + self::$bind = ['type' => 'class', 'class' => substr($result, 1)]; + } else { + // 绑定到模块/控制器 例如 index/user + self::$bind = ['type' => 'module', 'module' => $result]; + } + self::$domainBind = true; } else { - // 绑定到模块/控制器 例如 index/user - self::$bind = ['type' => 'module', 'module' => $result]; + self::$domainRule = $item; + $currentRules = isset($item[$method]) ? $item[$method] : $item['*']; } } } @@ -762,13 +787,12 @@ class Route } } $method = $request->method(); - // 检测域名部署 - if ($checkDomain) { - self::checkDomain($request, $method); - } // 获取当前请求类型的路由规则 $rules = self::$rules[$method]; - + // 检测域名部署 + if ($checkDomain) { + self::checkDomain($request, $rules, $method); + } // 检测URL绑定 $return = self::checkUrlBind($url, $rules, $depr); if (false !== $return) { @@ -781,7 +805,7 @@ class Route // 静态路由规则检测 $rule = $rules[$url]; if (true === $rule) { - $rule = self::$rules['*'][$url]; + $rule = self::getRouteExpress($url); } if (!empty($rule['route'])) { return self::parseRule($url, $rule['route'], $url, $rule['option']); @@ -795,6 +819,11 @@ class Route return false; } + private static function getRouteExpress($key) + { + return self::$domainRule ? self::$domainRule['*'][$key] : self::$rules['*'][$key]; + } + /** * 检测路由规则 * @access private @@ -809,7 +838,7 @@ class Route { foreach ($rules as $key => $item) { if (true === $item) { - $item = self::$rules['*'][$key]; + $item = self::getRouteExpress($key); } if (!isset($item['rule'])) { continue; @@ -925,7 +954,7 @@ class Route return self::bindToNamespace($url, $bind, $depr); case 'module': // 如果有模块/控制器绑定 针对路由到 模块/控制器 有效 - $url = (empty(self::$domain) ? $bind . '/' : '') . ltrim($url, '/'); + $url = (empty(self::$domainBind) ? $bind . '/' : '') . ltrim($url, '/'); break; } } diff --git a/core/library/think/Url.php b/core/library/think/Url.php index c2b6de21..2d2acb82 100644 --- a/core/library/think/Url.php +++ b/core/library/think/Url.php @@ -19,6 +19,9 @@ use think\Route; class Url { + // 生成URL地址的root + protected static $root; + /** * URL生成 支持路由反射 * @param string $url URL表达式, @@ -75,6 +78,9 @@ class Url if ($rule && $match = self::getRuleUrl($rule, $vars)) { // 匹配路由命名标识 快速生成 $url = $match; + if (!empty($rule[2])) { + $domain = $rule[2]; + } } elseif ($rule && isset($name)) { throw new \InvalidArgumentException('route name not exists:' . $name); } else { @@ -86,7 +92,7 @@ class Url $url = $match; } else { // 路由不存在 直接解析 - $url = self::parseUrl($url); + $url = self::parseUrl($url, $domain); } } @@ -126,12 +132,12 @@ class Url // 检测域名 $domain = self::parseDomain($url, $domain); // URL组装 - $url = $domain . Request::instance()->root() . '/' . ltrim($url, '/'); + $url = $domain . (self::$root ?: Request::instance()->root()) . '/' . ltrim($url, '/'); return $url; } // 直接解析URL地址 - protected static function parseUrl($url) + protected static function parseUrl($url, $domain) { $request = Request::instance(); if (0 === strpos($url, '/')) { @@ -145,8 +151,17 @@ class Url $url = substr($url, 1); } else { // 解析到 模块/控制器/操作 - $module = $request->module(); - $module = $module ? $module . '/' : ''; + $module = $request->module(); + $domains = Route::rules('domain'); + if (isset($domains[$domain]['[bind]'][0])) { + $bindModule = $domains[$domain]['[bind]'][0]; + if ($bindModule && !in_array($bindModule[0], ['\\', '@'])) { + $module = ''; + } + } else { + $module = $module ? $module . '/' : ''; + } + $controller = $request->controller(); if ('' == $url) { // 空字符串输出当前的 模块/控制器/操作 @@ -181,7 +196,7 @@ class Url if (0 === strpos($domain_prefix, '*.') && strpos($domain, ltrim($domain_prefix, '*.')) !== false) { foreach ($domains as $key => $rule) { $rule = is_array($rule) ? $rule[0] : $rule; - if (false === strpos($key, '*') && 0 === strpos($url, $rule)) { + if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) { $url = ltrim($url, $rule); $domain = $key; // 生成对应子域名 @@ -342,4 +357,11 @@ class Url { Cache::rm('think_route_map'); } -} \ No newline at end of file + + // 指定当前生成URL地址的root + public static function root($root) + { + self::$root = $root; + Request::instance()->root($root); + } +} diff --git a/core/library/think/Validate.php b/core/library/think/Validate.php index 7f230db8..857a9933 100644 --- a/core/library/think/Validate.php +++ b/core/library/think/Validate.php @@ -551,7 +551,7 @@ class Validate break; case 'boolean': // 是否为布尔值 - $result = $this->filter($value, FILTER_VALIDATE_BOOLEAN); + $result = in_array($value, [0, 1, true, false]); break; case 'array': // 是否为数组 diff --git a/core/library/think/db/Connection.php b/core/library/think/db/Connection.php index 38887b09..b92aea6d 100644 --- a/core/library/think/db/Connection.php +++ b/core/library/think/db/Connection.php @@ -226,13 +226,17 @@ abstract class Connection /** * 设置数据库的配置参数 * @access public - * @param string $config 配置名称 - * @param mixed $value 配置值 + * @param string|array $config 配置名称 + * @param mixed $value 配置值 * @return void */ - public function setConfig($config, $value) + public function setConfig($config, $value = '') { - $this->config[$config] = $value; + if (is_array($config)) { + $this->config = array_merge($this->config, $config); + } else { + $this->config[$config] = $value; + } } /** @@ -247,7 +251,7 @@ abstract class Connection public function connect(array $config = [], $linkNum = 0, $autoConnection = false) { if (!isset($this->links[$linkNum])) { - if (empty($config)) { + if (!$config) { $config = $this->config; } // 连接参数 @@ -281,20 +285,6 @@ abstract class Connection return $this->links[$linkNum]; } - /** - * 获取当前数据库的驱动类型 - * @access public - * @return string - */ - public function getDriverName() - { - if ($this->linkID) { - return $this->linkID->getAttribute(PDO::ATTR_DRIVER_NAME); - } else { - return $this->config['type']; - } - } - /** * 释放查询结果 * @access public diff --git a/core/library/think/db/Query.php b/core/library/think/db/Query.php index d838dc39..33d2d1f6 100644 --- a/core/library/think/db/Query.php +++ b/core/library/think/db/Query.php @@ -59,7 +59,7 @@ class Query public function __construct(Connection $connection = null, $model = '') { $this->connection = $connection ?: Db::connect([], true); - $this->driver = $this->connection->getDriverName(); + $this->driver = $this->connection->getConfig('type'); $this->prefix = $this->connection->getConfig('prefix'); $this->model = $model; } diff --git a/core/library/think/db/connector/Sqlsrv.php b/core/library/think/db/connector/Sqlsrv.php index 31cf9045..cce0c6c8 100644 --- a/core/library/think/db/connector/Sqlsrv.php +++ b/core/library/think/db/connector/Sqlsrv.php @@ -74,6 +74,12 @@ class Sqlsrv extends Connection ]; } } + $sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetch(PDO::FETCH_ASSOC); + if ($result) { + $info[$result['column_name']]['primary'] = true; + } return $this->fieldCase($info); } diff --git a/core/library/think/model/Merge.php b/core/library/think/model/Merge.php index 1bf634f4..9a28ea9c 100644 --- a/core/library/think/model/Merge.php +++ b/core/library/think/model/Merge.php @@ -189,8 +189,12 @@ class Merge extends Model if (!empty($where)) { $pk = $this->getPk(); - if (is_string($pk) && isset($data[$pk])) { - unset($data[$pk]); + + if (isset($this->mapFields[$pk])) { + $pk = $this->mapFields[$pk]; + } + if (isset($where[$pk])) { + unset($where[$pk]); } }