Jonlin 6 years ago
parent
commit
3bbee88457
100 changed files with 4598 additions and 2156 deletions
  1. 7 3
      application/admin/controller/Admins.php
  2. 3 3
      application/admin/controller/Groups.php
  3. 116 0
      application/admin/controller/Kfnotice.php
  4. 2 2
      application/admin/controller/Robot.php
  5. 54 20
      application/admin/controller/System.php
  6. 3 3
      application/admin/controller/Users.php
  7. 2 2
      application/admin/controller/Words.php
  8. 14 0
      application/admin/model/Servicenotice.php
  9. 44 0
      application/admin/model/Systemconfig.php
  10. 12 0
      application/admin/model/Users.php
  11. 110 0
      application/admin/view/kfnotice/add.html
  12. 129 0
      application/admin/view/kfnotice/index.html
  13. 22 3
      application/admin/view/menu.html
  14. 1 1
      application/admin/view/system/basics.html
  15. 157 0
      application/admin/view/system/conversation.html
  16. 38 1
      application/index/controller/Evaluate.php
  17. 2 1
      application/index/controller/Groups.php
  18. 4 2
      application/index/controller/Robot.php
  19. 2 2
      application/index/controller/Upload.php
  20. 29 0
      application/index/model/ServiceLog.php
  21. 9 0
      application/service/controller/Common.php
  22. 33 0
      application/service/controller/Dinterface.php
  23. 6 3
      application/service/controller/History.php
  24. 6 3
      application/service/controller/Index.php
  25. 36 23
      application/service/controller/Upload.php
  26. 21 21
      application/service/controller/Words.php
  27. 11 0
      composer.json
  28. 1 1
      public/static/service/js/whisper.js
  29. 2 2
      thinkphp/CONTRIBUTING.md
  30. 1 1
      thinkphp/LICENSE.txt
  31. 2 2
      thinkphp/README.md
  32. 4 2
      thinkphp/base.php
  33. 9 0
      thinkphp/convention.php
  34. 1 1
      thinkphp/helper.php
  35. 120 53
      thinkphp/lang/zh-cn.php
  36. 264 178
      thinkphp/library/think/App.php
  37. 90 60
      thinkphp/library/think/Build.php
  38. 68 43
      thinkphp/library/think/Cache.php
  39. 209 118
      thinkphp/library/think/Collection.php
  40. 99 63
      thinkphp/library/think/Config.php
  41. 266 122
      thinkphp/library/think/Console.php
  42. 57 41
      thinkphp/library/think/Controller.php
  43. 104 60
      thinkphp/library/think/Cookie.php
  44. 50 26
      thinkphp/library/think/Db.php
  45. 84 44
      thinkphp/library/think/Debug.php
  46. 8 5
      thinkphp/library/think/Env.php
  47. 44 28
      thinkphp/library/think/Error.php
  48. 11 10
      thinkphp/library/think/Exception.php
  49. 156 93
      thinkphp/library/think/File.php
  50. 37 25
      thinkphp/library/think/Hook.php
  51. 84 42
      thinkphp/library/think/Lang.php
  52. 302 195
      thinkphp/library/think/Loader.php
  53. 102 78
      thinkphp/library/think/Log.php
  54. 181 43
      thinkphp/library/think/Model.php
  55. 11 3
      thinkphp/library/think/Paginator.php
  56. 133 88
      thinkphp/library/think/Request.php
  57. 2 4
      thinkphp/library/think/Response.php
  58. 180 138
      thinkphp/library/think/Route.php
  59. 1 1
      thinkphp/library/think/Session.php
  60. 17 25
      thinkphp/library/think/Template.php
  61. 15 10
      thinkphp/library/think/Url.php
  62. 181 102
      thinkphp/library/think/Validate.php
  63. 12 9
      thinkphp/library/think/View.php
  64. 8 2
      thinkphp/library/think/cache/Driver.php
  65. 34 16
      thinkphp/library/think/cache/driver/File.php
  66. 2 2
      thinkphp/library/think/cache/driver/Lite.php
  67. 2 2
      thinkphp/library/think/cache/driver/Memcache.php
  68. 1 1
      thinkphp/library/think/cache/driver/Memcached.php
  69. 25 16
      thinkphp/library/think/cache/driver/Redis.php
  70. 2 2
      thinkphp/library/think/cache/driver/Sqlite.php
  71. 1 1
      thinkphp/library/think/cache/driver/Wincache.php
  72. 1 1
      thinkphp/library/think/cache/driver/Xcache.php
  73. 1 1
      thinkphp/library/think/config/driver/Ini.php
  74. 1 1
      thinkphp/library/think/config/driver/Json.php
  75. 1 1
      thinkphp/library/think/config/driver/Xml.php
  76. 11 2
      thinkphp/library/think/console/command/Clear.php
  77. 1 1
      thinkphp/library/think/console/command/optimize/Config.php
  78. 5 0
      thinkphp/library/think/console/command/optimize/Route.php
  79. 4 2
      thinkphp/library/think/console/command/optimize/Schema.php
  80. 3 3
      thinkphp/library/think/controller/Rest.php
  81. 85 50
      thinkphp/library/think/db/Builder.php
  82. 62 36
      thinkphp/library/think/db/Connection.php
  83. 48 0
      thinkphp/library/think/db/Expression.php
  84. 379 165
      thinkphp/library/think/db/Query.php
  85. 75 6
      thinkphp/library/think/db/builder/Mysql.php
  86. 9 3
      thinkphp/library/think/db/builder/Pgsql.php
  87. 9 3
      thinkphp/library/think/db/builder/Sqlite.php
  88. 32 18
      thinkphp/library/think/db/builder/Sqlsrv.php
  89. 1 1
      thinkphp/library/think/db/connector/Mysql.php
  90. 1 1
      thinkphp/library/think/db/connector/Pgsql.php
  91. 1 1
      thinkphp/library/think/db/connector/Sqlite.php
  92. 4 1
      thinkphp/library/think/db/connector/Sqlsrv.php
  93. 1 1
      thinkphp/library/think/db/exception/BindParamException.php
  94. 1 1
      thinkphp/library/think/db/exception/DataNotFoundException.php
  95. 1 1
      thinkphp/library/think/db/exception/ModelNotFoundException.php
  96. 1 1
      thinkphp/library/think/debug/Console.php
  97. 1 1
      thinkphp/library/think/debug/Html.php
  98. 1 1
      thinkphp/library/think/exception/DbException.php
  99. 1 1
      thinkphp/library/think/exception/ErrorException.php
  100. 1 1
      thinkphp/library/think/exception/PDOException.php

+ 7 - 3
application/admin/controller/Admins.php

@@ -86,7 +86,7 @@ class Admins extends Base
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('addadmin');
     }
     }
 
 
     // 编辑管理员
     // 编辑管理员
@@ -125,7 +125,7 @@ class Admins extends Base
             'info' => $info,
             'info' => $info,
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
-        return $this->fetch();
+        return $this->fetch('editadmin');
     }
     }
 
 
     // 删除管理员
     // 删除管理员
@@ -271,6 +271,7 @@ class Admins extends Base
 
 
         return $operate;
         return $operate;
     }
     }
+<<<<<<< HEAD
 
 
     // 生成权限组操作按钮
     // 生成权限组操作按钮
     private function makeBtnPower($id)
     private function makeBtnPower($id)
@@ -283,4 +284,7 @@ class Admins extends Base
 
 
         return $operate;
         return $operate;
     }
     }
-}
+}
+=======
+}
+>>>>>>> d7221b8b22f990bd668469d6f4bdea47bec592b5

+ 3 - 3
application/admin/controller/Groups.php

@@ -71,7 +71,7 @@ class Groups extends Base
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('addgroup');
     }
     }
 
 
     // 编辑分组
     // 编辑分组
@@ -103,7 +103,7 @@ class Groups extends Base
             'info' => $info,
             'info' => $info,
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
-        return $this->fetch();
+        return $this->fetch('editgroup');
     }
     }
 
 
     // 删除分组
     // 删除分组
@@ -148,4 +148,4 @@ class Groups extends Base
 
 
         return $operate;
         return $operate;
     }
     }
-}
+}

+ 116 - 0
application/admin/controller/Kfnotice.php

@@ -0,0 +1,116 @@
+<?php
+/**
+ * User: nickbai
+ * Date: 2017/10/23 13:33
+ * Email: 1902822973@qq.com
+ */
+namespace app\admin\controller;
+
+use app\admin\model\Servicenotice as ServicenoticeModel;
+use app\admin\model\Users as Usersmodel;
+
+class Kfnotice extends Base
+{
+    // 管理员列表
+    public function index()
+    {
+
+        if(request()->isAjax()){
+
+            $param = input('param.');
+
+            $limit = $param['pageSize'];
+            $offset = ($param['pageNumber'] - 1) * $limit;
+
+            $where = [];
+            if (!empty($param['searchText'])) {
+                $where['atext'] = ['like', '%' . $param['searchText'] . '%'];
+            }
+
+            $model = new ServicenoticeModel();
+            $result = $model->where($where)->limit($offset, $limit)->order('id','desc')->select();
+
+            foreach($result as $key=>$vo){
+                $vo->readtime = empty($vo->readtime) ? '' : date('Y-m-d H:i:s', $vo->readtime);
+                $vo->uid = $vo->kfuser->user_name;
+                $result[$key] = array_merge($vo->toArray(),['operate'=>$this->makeBtn($vo->id)]) ;
+            }
+            $return['total'] = db('servicenotice')->where($where)->count();  //总数据
+            $return['rows'] = $result;
+
+            return json($return);
+
+        }
+
+        return $this->fetch();
+    }
+
+    // 添加管理员
+    public function add()
+    {
+        if(request()->isPost()){
+
+            $atext = input('post.atext');
+
+            if (empty($atext)){
+                return json(['code' => -1, 'data' => '', 'msg' => '内容不能为空']);
+            }
+
+            $Users = (new Usersmodel())->where(['status'=>1])->select();
+            if (!$Users){
+                return json(['code' => -2, 'data' => '', 'msg' => '没有可用客服']);
+            }
+
+            $datas = [] ;
+            foreach ($Users as $val){
+                $arr = [
+                    'uid'=>$val->id,
+                    'atext'=>$atext
+                ];
+                $datas[] = $arr;
+            }
+
+            try{
+                db('servicenotice')->insertAll($datas);
+            }catch(\Exception $e){
+                return json(['code' => -2, 'data' => '', 'msg' => $e->getMessage()]);
+            }
+            return json(['code' => 1, 'data' => '', 'msg' => '添加公告成功']);
+        }
+
+        $this->assign([
+            'status' => config('kf_status')
+        ]);
+
+        return $this->fetch();
+    }
+
+
+    // 删除管理员
+    public function del()
+    {
+        if(request()->isAjax()){
+            $id = input('param.id/d');
+            //return $id;
+
+            try{
+                db('servicenotice')->where('id', $id)->delete();
+            }catch(\Exception $e){
+                return json(['code' => -1, 'data' => '', 'msg' => $e->getMessage()]);
+            }
+
+            return json(['code' => 1, 'data' => '', 'msg' => '删除成功']);
+        }
+    }
+
+
+
+    // 生成按钮
+    private function makeBtn($id)
+    {
+        $operate = '<a href="javascript:adminDel(' . $id . ')"><button type="button" class="btn btn-danger btn-sm">';
+        $operate .= '<i class="fa fa-trash-o"></i> 删除</button></a> ';
+
+        return $operate;
+    }
+}

+ 2 - 2
application/admin/controller/Robot.php

@@ -98,7 +98,7 @@ class Robot extends Base
             'robotgroups' => $robotgroups,
             'robotgroups' => $robotgroups,
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('addword');
     }
     }
 
 
     // 编辑智能问答
     // 编辑智能问答
@@ -142,7 +142,7 @@ class Robot extends Base
             'robotgroups' => $robotgroups,
             'robotgroups' => $robotgroups,
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
-        return $this->fetch();
+        return $this->fetch('editword');
     }
     }
 
 
     // 删除智能问答
     // 删除智能问答

+ 54 - 20
application/admin/controller/System.php

@@ -64,6 +64,59 @@ class System extends Base
     }//end basics()
     }//end basics()
 
 
 
 
+    /**
+     * 会话设置
+     *
+     * @access public
+     */
+    public function conversation()
+    {
+        // 表单提交.
+        if (request()->isPost()) {
+            $param = input('post.');
+
+            try {
+                // 修改会话超时.
+                $updateOvertimeData['systemconfig_data'] = $param['overtime'];
+                $updateOvertimeWhere['systemconfig_id']  = 1;
+                model('Systemconfig')->updateSystemconfig($updateOvertimeWhere, $updateOvertimeData);
+                // 修改访客静默.
+                $upUptdData['systemconfig_data'] = $param['unoperated'];
+                $upUptdWhere['systemconfig_id']  = 2;
+                model('Systemconfig')->updateSystemconfig($upUptdWhere, $upUptdData);
+                // 质检会话时长设置.
+                $upAllTimeData['systemconfig_data'] = $param['verifyAllTime'];
+                $upAllTimeWhere['systemconfig_id']  = 3;
+                model('Systemconfig')->updateSystemconfig($upAllTimeWhere, $upAllTimeData);
+                // 质检会话响应时长设置.
+                $upReturnTimeData['systemconfig_data'] = $param['verifyReturnTime'];
+                $upReturnTimeWhere['systemconfig_id']  = 4;
+                model('Systemconfig')->updateSystemconfig($upReturnTimeWhere, $upReturnTimeData);
+                // 满意度评价回合限制.
+                $upRoundData['systemconfig_data'] = $param['round'];
+                $upRoundWhere['systemconfig_id']  = 5;
+                model('Systemconfig')->updateSystemconfig($upRoundWhere, $upRoundData);
+
+                return json(['code' => 1, 'data' => '', 'msg' => '设置成功']);
+            } catch (\Exception $e) {
+                return json(['code' => -2, 'data' => '', 'msg' => $e->getMessage()]);
+            }//end try
+        }//end if
+
+        // 获取设置.
+        $systemconfig = model('Systemconfig')->selectSystemconfig();
+        $this->assign(
+            [
+                'systemconfig' => $systemconfig,
+                'status'       => config('kf_status'),
+            ]
+        );
+
+        return $this->fetch();
+
+    }//end conversation()
+
+
     // 自动回复设置
     // 自动回复设置
     public function reply()
     public function reply()
     {
     {
@@ -92,25 +145,6 @@ class System extends Base
         return $this->fetch();
         return $this->fetch();
     }
     }
 
 
-    // 客服设置
-    public function customerService()
-    {
-        if(request()->isPost()){
-
-            $param = input('post.');
-            db('kf_config')->where('id', 1)->update($param);
-
-            return json(['code' => 1, 'data' => '', 'msg' => '设置成功']);
-        }
-
-        $this->assign([
-            'config' => db('kf_config')->where('id', 1)->find(),
-            'status' => config('kf_status')
-        ]);
-
-        return $this->fetch();
-    }
-
     // 历史会话记录
     // 历史会话记录
     public function wordsLog()
     public function wordsLog()
     {
     {
@@ -241,7 +275,7 @@ class System extends Base
             'groupoption' => $groupoption
             'groupoption' => $groupoption
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('wordslog');
     }
     }
 
 
 
 

+ 3 - 3
application/admin/controller/Users.php

@@ -107,7 +107,7 @@ class Users extends Base
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('adduser');
     }
     }
 
 
     // 编辑客服
     // 编辑客服
@@ -169,7 +169,7 @@ class Users extends Base
             'status' => config('kf_status'),
             'status' => config('kf_status'),
             'groups' => db('groups')->select()
             'groups' => db('groups')->select()
         ]);
         ]);
-        return $this->fetch();
+        return $this->fetch('edituser');
     }
     }
 
 
     public function resetPwd(){
     public function resetPwd(){
@@ -237,4 +237,4 @@ class Users extends Base
 
 
         return $operate;
         return $operate;
     }
     }
-}
+}

+ 2 - 2
application/admin/controller/Words.php

@@ -73,7 +73,7 @@ class Words extends Base
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
 
 
-        return $this->fetch();
+        return $this->fetch('addword');
     }
     }
 
 
     // 编辑常用语
     // 编辑常用语
@@ -106,7 +106,7 @@ class Words extends Base
             'info' => $info,
             'info' => $info,
             'status' => config('kf_status')
             'status' => config('kf_status')
         ]);
         ]);
-        return $this->fetch();
+        return $this->fetch('editword');
     }
     }
 
 
     // 删除常用语
     // 删除常用语

+ 14 - 0
application/admin/model/Servicenotice.php

@@ -0,0 +1,14 @@
+<?php
+namespace app\admin\model;
+
+use think\Model;
+
+
+class Servicenotice extends Model
+{
+    public function kfuser()
+    {
+        return $this->belongsTo('Users','uid','id');
+    }
+
+}

+ 44 - 0
application/admin/model/Systemconfig.php

@@ -0,0 +1,44 @@
+<?php
+namespace app\admin\model;
+
+use think\Model;
+
+/**
+ * 系统设置模型
+ */
+class Systemconfig extends Model
+{
+
+
+    /**
+     * 数据筛选
+     *
+     * @access public
+     * @param mixed $where 数据
+     * @return array 返回类型
+     */
+    public function selectSystemconfig()
+    {
+        $result = $this->order('systemconfig_id')->select();
+        return $result;
+
+    }//end selectSystemconfig()
+
+
+    /**
+     * 数据修改
+     *
+     * @access public
+     * @param mixed $data 数据
+     * @param mixed $where 条件
+     * @return array 返回类型
+     */
+    public function updateSystemconfig($where, $data)
+    {
+        $result = $this->where($where)->update($data);
+        return $result;
+
+    }//end updateReply()
+
+
+}

+ 12 - 0
application/admin/model/Users.php

@@ -0,0 +1,12 @@
+<?php
+namespace app\admin\model;
+
+use think\Model;
+
+/**
+ * 分组模型
+ */
+class Users extends Model
+{
+
+}

+ 110 - 0
application/admin/view/kfnotice/add.html

@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>添加公告</title>
+    <link rel="shortcut icon" href="favicon.ico">
+    <link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
+    <link href="__CSS__/font-awesome.min.css?v=4.4.0" rel="stylesheet">
+    <link href="__CSS__/animate.min.css" rel="stylesheet">
+    <link href="__JS__/layui/css/layui.css" rel="stylesheet">
+    <link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
+</head>
+<body class="gray-bg">
+<div class="wrapper wrapper-content animated fadeInRight">
+    <div class="row">
+        <div class="col-sm-8">
+            <div class="ibox float-e-margins">
+                <div class="ibox-title">
+                    <h5>添加公告</h5>
+                </div>
+                <div class="ibox-content">
+                    <form class="form-horizontal m-t layui-form" id="commentForm" method="post" action="{:url('kfnotice/add')}">
+
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">内容:</label>
+                            <div class="input-group col-sm-4">
+                                <textarea name="atext" id="atext" required="true" placeholder="请输入内容" class="layui-textarea"></textarea>
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <div class="col-sm-4 col-sm-offset-6">
+                                <button class="btn btn-primary" type="submit">提交</button>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</div>
+<script src="__JS__/jquery.min.js?v=2.1.4"></script>
+<script src="__JS__/bootstrap.min.js?v=3.3.6"></script>
+<script src="__JS__/content.min.js?v=1.0.0"></script>
+<script src="__JS__/plugins/validate/jquery.validate.min.js"></script>
+<script src="__JS__/plugins/validate/messages_zh.min.js"></script>
+<script src="__JS__/plugins/layer/layer.min.js"></script>
+<script src="__JS__/layui/layui.js"></script>
+<script src="__JS__/jquery.form.js"></script>
+<script type="text/javascript">
+
+    layui.use(['form', 'upload'], function(){
+        var form = layui.form;
+    });
+
+    var index = '';
+    function showStart(){
+        index = layer.load(0, {shade: false});
+        return true;
+    }
+
+    function showSuccess(res){
+
+        layer.ready(function(){
+            layer.close(index);
+            if(1 == res.code){
+               layer.alert(res.msg, {title: '友情提示', icon: 1, closeBtn: 0}, function(){
+                   window.location.href = res.data;
+               });
+            }else if(111 == res.code){
+                window.location.reload();
+            }else{
+                layer.msg(res.msg, {anim: 6});
+            }
+        });
+    }
+
+    $(document).ready(function(){
+        // 添加管理员
+        var options = {
+            beforeSubmit:showStart,
+            success:showSuccess
+        };
+
+        $('#commentForm').submit(function(){
+            $(this).ajaxSubmit(options);
+            return false;
+        });
+    });
+
+    // 表单验证
+    $.validator.setDefaults({
+        highlight: function(e) {
+            $(e).closest(".form-group").removeClass("has-success").addClass("has-error")
+        },
+        success: function(e) {
+            e.closest(".form-group").removeClass("has-error").addClass("has-success")
+        },
+        errorElement: "span",
+        errorPlacement: function(e, r) {
+            e.appendTo(r.is(":radio") || r.is(":checkbox") ? r.parent().parent().parent() : r.parent())
+        },
+        errorClass: "help-block m-b-none",
+        validClass: "help-block m-b-none"
+    });
+
+</script>
+</body>
+</html>

+ 129 - 0
application/admin/view/kfnotice/index.html

@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>管理员列表</title>
+    <link rel="shortcut icon" href="favicon.ico">
+    <link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
+    <link href="__CSS__/font-awesome.min.css?v=4.4.0" rel="stylesheet">
+    <link href="__CSS__/plugins/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
+    <link href="__CSS__/animate.min.css" rel="stylesheet">
+    <link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
+</head>
+<body class="gray-bg">
+<div class="wrapper wrapper-content animated fadeInRight">
+    <!-- Panel Other -->
+    <div class="ibox float-e-margins">
+        <div class="ibox-title">
+            <h5>管理员列表</h5>
+        </div>
+        <div class="ibox-content">
+            <!--搜索框开始-->
+            <form id='commentForm' role="form" method="post" class="form-inline pull-right">
+                <div class="content clearfix m-b">
+                    <div class="form-group">
+                        <label>模糊搜索内容:</label>
+                        <input type="text" class="form-control" id="username" name="user_name">
+                    </div>
+                    <div class="form-group">
+                        <button class="btn btn-primary" type="button" style="margin-top:5px" id="search"><strong>搜 索</strong>
+                        </button>
+                    </div>
+                </div>
+            </form>
+            <!--搜索框结束-->
+            <div class="example-wrap">
+                <div class="example">
+                    <table id="cusTable">
+                        <thead>
+                        <th data-field="id">ID</th>
+                        <th data-field="uid">uid</th>
+                        <th data-field="atext">内容</th>
+                        <th data-field="ctime">发布时间</th>
+                        <th data-field="readtime">读时间</th>
+                        <th data-field="operate">操作</th>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <!-- End Example Pagination -->
+        </div>
+    </div>
+</div>
+<!-- End Panel Other -->
+<script src="__JS__/jquery.min.js?v=2.1.4"></script>
+<script src="__JS__/bootstrap.min.js?v=3.3.6"></script>
+<script src="__JS__/content.min.js?v=1.0.0"></script>
+<script src="__JS__/plugins/bootstrap-table/bootstrap-table.min.js"></script>
+<script src="__JS__/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
+<script src="__JS__/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
+<script src="__JS__/plugins/layer/layer.min.js"></script>
+<script type="text/javascript">
+    function initTable() {
+        //先销毁表格
+        $('#cusTable').bootstrapTable('destroy');
+        //初始化表格,动态从服务器加载数据
+        $("#cusTable").bootstrapTable({
+            method: "get",  //使用get请求到服务器获取数据
+            url: "{:url('kfnotice/index')}", //获取数据的地址
+            striped: true,  //表格显示条纹
+            pagination: true, //启动分页
+            pageSize: 10,  //每页显示的记录数
+            pageNumber:1, //当前第几页
+            pageList: [5, 10, 15, 20, 25],  //记录数可选列表
+            sidePagination: "server", //表示服务端请求
+            paginationFirstText: "首页",
+            paginationPreText: "上一页",
+            paginationNextText: "下一页",
+            paginationLastText: "尾页",
+            queryParamsType : "undefined",
+            queryParams: function queryParams(params) {   //设置查询参数
+                var param = {
+                    pageNumber: params.pageNumber,
+                    pageSize: params.pageSize,
+                    searchText:$('#username').val()
+                };
+                return param;
+            },
+            onLoadSuccess: function(res){  //加载成功时执行
+                if(111 == res.code){
+                    window.location.reload();
+                }
+                layer.msg("加载成功", {time : 1000});
+            },
+            onLoadError: function(){  //加载失败时执行
+                layer.msg("加载数据失败");
+            }
+        });
+    }
+
+    $(document).ready(function () {
+        //调用函数,初始化表格
+        initTable();
+
+        //当点击查询按钮的时候执行
+        $("#search").bind("click", initTable);
+    });
+
+    function adminDel(id) {
+        layer.confirm('确认删除记录?', {icon: 3, title: '提示'}, function (index) {
+            //do something
+            $.getJSON("{:url('kfnotice/del')}", {'id': id}, function (res) {
+                if (1 == res.code) {
+                    layer.alert(res.msg, {title: '友情提示', icon: 1, closeBtn: 0}, function () {
+                        initTable();
+                    });
+                } else if (111 == res.code) {
+                    window.location.reload();
+                } else {
+                    layer.alert(res.msg, {title: '友情提示', icon: 2});
+                }
+            });
+
+            layer.close(index);
+        })
+    }
+</script>
+</body>
+</html>

+ 22 - 3
application/admin/view/menu.html

@@ -116,10 +116,10 @@
             <a class="J_menuItem" href="{:url('system/basics')}">基础设置</a>
             <a class="J_menuItem" href="{:url('system/basics')}">基础设置</a>
         </li>
         </li>
         <li>
         <li>
-            <a class="J_menuItem" href="{:url('system/reply')}">自动回复设置</a>
+            <a class="J_menuItem" href="{:url('system/conversation')}">会话设置</a>
         </li>
         </li>
         <li>
         <li>
-            <a class="J_menuItem" href="{:url('system/customerService')}">客服设置</a>
+            <a class="J_menuItem" href="{:url('system/reply')}">自动回复设置</a>
         </li>
         </li>
     </ul>
     </ul>
 </li>
 </li>
@@ -209,6 +209,7 @@
         }
         }
     });
     });
 
 
+<<<<<<< HEAD
     $n = 1;
     $n = 1;
     $(document).on("click","#side-menu>li",function(){
     $(document).on("click","#side-menu>li",function(){
         console.log(1234);
         console.log(1234);
@@ -223,4 +224,22 @@
             $n = 1;
             $n = 1;
         }
         }
     });
     });
-</script>
+</script>
+=======
+<li class="menu">
+    <a href="#">
+        <i class="fa fa-comments-o"></i>
+        <span class="nav-label">客服公告</span>
+        <span class="fa arrow"></span>
+    </a>
+    <ul class="nav nav-second-level">
+        <li>
+            <a class="J_menuItem" href="{:url('kfnotice/index')}">公告列表</a>
+        </li>
+        <li>
+            <a class="J_menuItem" href="{:url('kfnotice/add')}">添加公告</a>
+        </li>
+    </ul>
+</li>
+
+>>>>>>> d7221b8b22f990bd668469d6f4bdea47bec592b5

+ 1 - 1
application/admin/view/system/basics.html

@@ -66,7 +66,7 @@
                                 {/if}
                                 {/if}
                             </div>
                             </div>
                         </div>
                         </div>
-                        <div class="form-group">
+                        <div class="form-group" style="margin-top: 40px;">
                             <label class="col-sm-3 control-label"></label>
                             <label class="col-sm-3 control-label"></label>
                             <div class="input-group col-sm-4">
                             <div class="input-group col-sm-4">
                                 <button class="btn btn-primary" type="submit">提交</button>
                                 <button class="btn btn-primary" type="submit">提交</button>

+ 157 - 0
application/admin/view/system/conversation.html

@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>编辑管理员</title>
+    <link rel="shortcut icon" href="favicon.ico">
+    <link href="__CSS__/bootstrap.min.css?v=3.3.6" rel="stylesheet">
+    <link href="__CSS__/font-awesome.min.css?v=4.4.0" rel="stylesheet">
+    <link href="__CSS__/animate.min.css" rel="stylesheet">
+    <link href="__JS__/layui/css/layui.css" rel="stylesheet">
+    <link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
+</head>
+<body class="gray-bg">
+<div class="wrapper wrapper-content animated fadeInRight">
+    <div class="row">
+        <div class="col-sm-8">
+            <div class="ibox float-e-margins">
+                <div class="ibox-title">
+                    <h5>会话设置</h5>
+                </div>
+                <div class="ibox-content">
+                    <form class="form-horizontal m-t layui-form" id="commentForm" method="post" action="{:url('system/conversation')}">
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">会话超时设置:</label>
+                            <div class="input-group col-sm-1">
+                                <input type="text" class="form-control" name="overtime" required="" aria-required="true" value="{$systemconfig[0]['systemconfig_data']}">
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">访客静默设置:</label>
+                            <div class="input-group col-sm-1">
+                                <input type="text" class="form-control" name="unoperated" required="" aria-required="true" value="{$systemconfig[1]['systemconfig_data']}">
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">会话时长设置:</label>
+                            <div class="input-group col-sm-1">
+                                <input type="text" class="form-control" name="verifyAllTime" required="" aria-required="true" value="{$systemconfig[2]['systemconfig_data']}">
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">会话响应时长设置:</label>
+                            <div class="input-group col-sm-1">
+                                <input type="text" class="form-control" name="verifyReturnTime" required="" aria-required="true" value="{$systemconfig[3]['systemconfig_data']}">
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-3 control-label">满意度评价回合限制:</label>
+                            <div class="input-group col-sm-1" style="width: 45px">
+                                <input type="text" class="form-control" name="round" required="" aria-required="true" value="{$systemconfig[4]['systemconfig_data']}">
+                            </div>
+                        </div>
+                        <div class="form-group" style="margin-top: 40px;">
+                            <label class="col-sm-3 control-label"></label>
+                            <div class="input-group col-sm-4">
+                                <button class="btn btn-primary" type="submit">提交</button>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</div>
+<script src="__JS__/jquery.min.js?v=2.1.4"></script>
+<script src="__JS__/bootstrap.min.js?v=3.3.6"></script>
+<script src="__JS__/content.min.js?v=1.0.0"></script>
+<script src="__JS__/plugins/validate/jquery.validate.min.js"></script>
+<script src="__JS__/plugins/validate/messages_zh.min.js"></script>
+<script src="__JS__/plugins/layer/layer.min.js"></script>
+<script src="__JS__/layui/layui.js"></script>
+<script src="__JS__/jquery.form.js"></script>
+<script type="text/javascript">
+
+    layui.use(['form', 'upload'], function(){
+        var form = layui.form;
+        var upload = layui.upload;
+        //执行实例
+        var uploadInst = upload.render({
+            elem: '#up-avatar' //绑定元素
+            ,url: "{:url('users/upAvatar')}" //上传接口
+            ,exts: 'png|jpg|jpeg|gif'
+            ,done: function(res){
+                //上传完毕回调
+                if(0 == res.code){
+                    $("#avatar").html('<img src="' + res.data.src + '" width="50px" height="50px">');
+                    $("#advertisement_img").val(res.data.src);
+                }else{
+                    layer.msg(res.msg);
+                }
+            }
+            ,error: function(){
+                //请求异常回调
+            }
+        });
+
+        form.on('select(group)', function(value){
+            $("#group_id").val(value.value);
+        });
+    });
+
+    var index = '';
+    function showStart(){
+        index = layer.load(0, {shade: false});
+        return true;
+    }
+
+    function showSuccess(res){
+
+        layer.ready(function(){
+            layer.close(index);
+            if(1 == res.code){
+                layer.alert(res.msg, {title: '友情提示', icon: 1, closeBtn: 0}, function(){
+                    window.location.href = res.data;
+                });
+            }else if(111 == res.code){
+                window.location.reload();
+            }else{
+                layer.msg(res.msg, {anim: 6});
+            }
+        });
+    }
+
+    $(document).ready(function(){
+        // 添加管理员
+        var options = {
+            beforeSubmit:showStart,
+            success:showSuccess
+        };
+
+        $('#commentForm').submit(function(){
+            $(this).ajaxSubmit(options);
+            return false;
+        });
+    });
+
+    // 表单验证
+    $.validator.setDefaults({
+        highlight: function(e) {
+            $(e).closest(".form-group").removeClass("has-success").addClass("has-error")
+        },
+        success: function(e) {
+            e.closest(".form-group").removeClass("has-error").addClass("has-success")
+        },
+        errorElement: "span",
+        errorPlacement: function(e, r) {
+            e.appendTo(r.is(":radio") || r.is(":checkbox") ? r.parent().parent().parent() : r.parent())
+        },
+        errorClass: "help-block m-b-none",
+        validClass: "help-block m-b-none"
+    });
+
+</script>
+</body>
+</html>

+ 38 - 1
application/index/controller/Evaluate.php

@@ -21,6 +21,7 @@ class Evaluate extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -28,7 +29,7 @@ class Evaluate extends Common
             // 获取数据.
             // 获取数据.
             $robot = model('Evaluate')->getEvaluate();
             $robot = model('Evaluate')->getEvaluate();
 
 
-            return json(['code' => 200, 'data' => $robot, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $robot, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -36,4 +37,40 @@ class Evaluate extends Common
     }//end index()
     }//end index()
 
 
 
 
+    /**
+     * 评价
+     *
+     * @access public
+     * @return array JsonString
+     */
+    public function putEvaluate()
+    {
+        // 验证token.
+        $tokenStatus = $this->verifyApiToken();
+        $code        = -2;
+        $msg         = '错误';
+        if ($tokenStatus === false) {
+            $msg = 'token错误';
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }
+
+        try {
+            // 获取数据.
+            $evaluateId                = input('get.evaluateId');
+            $conversationId            = input('get.conversationId');
+            $evaluateContent           = input('get.evaluateContent');
+            $where['servicelog_id']    = $conversationId;
+            $where['evaluate_content'] = $evaluateContent;
+            $data['evaluate_id']       = $evaluateId;
+            // 评价.
+            $result = model('serviceLog')->getEvaluate($where, $data);
+
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
+        } catch (\Exception $e) {
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }//end try
+
+    }//end putEvaluate()
+
+
 }
 }

+ 2 - 1
application/index/controller/Groups.php

@@ -22,6 +22,7 @@ class Groups extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -30,7 +31,7 @@ class Groups extends Common
             // 获取符合条件数据.
             // 获取符合条件数据.
             $groups = model('Groups')->select($groupsWhere);
             $groups = model('Groups')->select($groupsWhere);
 
 
-            return json(['code' => 200, 'data' => $groups, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $groups, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }

+ 4 - 2
application/index/controller/Robot.php

@@ -21,6 +21,7 @@ class Robot extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -41,7 +42,7 @@ class Robot extends Common
             // 获取符合条件数据.
             // 获取符合条件数据.
             $robot = model('Robot')->select($robotWhere);
             $robot = model('Robot')->select($robotWhere);
 
 
-            return json(['code' => 200, 'data' => $robot, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $robot, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -62,6 +63,7 @@ class Robot extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -70,7 +72,7 @@ class Robot extends Common
             // 获取符合条件数据.
             // 获取符合条件数据.
             $robotGroups = model('Robotgroups')->select($robotGroupsWhere);
             $robotGroups = model('Robotgroups')->select($robotGroupsWhere);
 
 
-            return json(['code' => 200, 'data' => $robotGroups, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $robotGroups, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }

+ 2 - 2
application/index/controller/Upload.php

@@ -29,7 +29,7 @@ class Upload extends Controller
         $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
         $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
         if($info){
         if($info){
             $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
             $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
-            return json(['code' => 200, 'data' => ['src' => $src ], 'msg' => '']);
+            return json(['code' => 1, 'data' => ['src' => $src ], 'msg' => '']);
         }else{
         }else{
             // 上传失败获取错误信息
             // 上传失败获取错误信息
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
@@ -60,7 +60,7 @@ class Upload extends Controller
         $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
         $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
         if($info){
         if($info){
             $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
             $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
-            return json(['code' => 200, 'data' => ['src' => $src ], 'msg' => $fileInfo['name']]);
+            return json(['code' => 1, 'data' => ['src' => $src ], 'msg' => $fileInfo['name']]);
         }else{
         }else{
             // 上传失败获取错误信息
             // 上传失败获取错误信息
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);

+ 29 - 0
application/index/model/ServiceLog.php

@@ -0,0 +1,29 @@
+<?php
+namespace app\index\model;
+
+use think\Model;
+
+/**
+ * 工单模型
+ */
+class ServiceLog extends Model
+{
+
+
+    /**
+     * 修改工单
+     *
+     * @access public
+     * @param mixed $where 条件
+     * @param mixed $data 条件
+     * @return array 返回类型
+     */
+    public function getEvaluate($where, $data)
+    {
+        $result = $this->where($where)->update($data);
+        return $result;
+
+    }//end getEvaluate()
+
+
+}

+ 9 - 0
application/service/controller/Common.php

@@ -23,7 +23,9 @@ class Common extends Base
         $controller   = $request->controller();
         $controller   = $request->controller();
         $module       = $request->module();
         $module       = $request->module();
         $apiToken     = md5(strtolower($action.'Customer-Service'.$controller.strtotime(date('Y-m-d')).$module));
         $apiToken     = md5(strtolower($action.'Customer-Service'.$controller.strtotime(date('Y-m-d')).$module));
+        //print_r([$apiToken,$getApiToken]);die;
         // 验证服务器token.
         // 验证服务器token.
+
         if ($getApiToken === $apiToken && empty($getUserToken) === false) {
         if ($getApiToken === $apiToken && empty($getUserToken) === false) {
             $usersField          = [
             $usersField          = [
                 'id',
                 'id',
@@ -47,6 +49,13 @@ class Common extends Base
 
 
     }//end verifyToken()
     }//end verifyToken()
 
 
+    protected  function  doTokenCheck(){
+        if (!$this->verifyToken()){
+            echo  json_encode(['code' => -1, 'data' => [], 'msg' => 'check false!'],256);
+            exit ;
+        }
+    }
+
 
 
     /**
     /**
      * 获取用户信息
      * 获取用户信息

+ 33 - 0
application/service/controller/Dinterface.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace app\service\controller;
+
+use app\admin\model\Servicenotice as ServicenoticeModel;
+
+/**
+ * 接口
+ */
+class Dinterface extends Common
+{
+
+    public function getNotice()
+    {
+        $this->doTokenCheck();
+
+        $uid = input('post.uid');
+        $uid = intval(trim($uid, 'KF'));
+        $rets = (new ServicenoticeModel())->where(['uid' => $uid, 'readtime' => 0])->order('id asc')->limit(20)->select();
+        if ($rets) {
+            foreach ($rets as $val) {
+                $val->readtime = time();
+                $val->save();
+            }
+        } else {
+            return json(['code' => 1, 'data' => [], 'msg' => 'success']);
+        }
+
+        return json(['code' => 1, 'data' => $rets, 'msg' => 'success']);
+    }
+
+
+}

+ 6 - 3
application/service/controller/History.php

@@ -21,6 +21,7 @@ class History extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -94,7 +95,7 @@ class History extends Common
             $result['list']        = $serviceLog;
             $result['list']        = $serviceLog;
             $result['pageSize']    = $pageSize;
             $result['pageSize']    = $pageSize;
 
 
-            return json(['code' => 200, 'data' => $result, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -115,6 +116,7 @@ class History extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -138,7 +140,7 @@ class History extends Common
             $result['list']        = $chatLog;
             $result['list']        = $chatLog;
             $result['pageSize']    = $pageSize;
             $result['pageSize']    = $pageSize;
 
 
-            return json(['code' => 200, 'data' => $result, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -159,6 +161,7 @@ class History extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -189,7 +192,7 @@ class History extends Common
             $result['list']        = $chatLog;
             $result['list']        = $chatLog;
             $result['pageSize']    = $pageSize;
             $result['pageSize']    = $pageSize;
 
 
-            return json(['code' => 200, 'data' => $result, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try

+ 6 - 3
application/service/controller/Index.php

@@ -21,6 +21,7 @@ class Index extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -38,7 +39,7 @@ class Index extends Common
             // 获取用户信息.
             // 获取用户信息.
             $usersInfo = model('users')->findInfo($usersField, $usersWhere, $join);
             $usersInfo = model('users')->findInfo($usersField, $usersWhere, $join);
 
 
-            return json(['code' => 200, 'data' => $usersInfo, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $usersInfo, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -59,6 +60,7 @@ class Index extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -84,7 +86,7 @@ class Index extends Common
                 'userWords' => $userWords,
                 'userWords' => $userWords,
             ];
             ];
 
 
-            return json(['code' => 200, 'data' => $result, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $result, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -105,6 +107,7 @@ class Index extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -126,7 +129,7 @@ class Index extends Common
                 'serverSensitive' => $serverSensitive,
                 'serverSensitive' => $serverSensitive,
             ];
             ];
 
 
-            return json(['code' => 200, 'data' => $data, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $data, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try

+ 36 - 23
application/service/controller/Upload.php

@@ -7,32 +7,45 @@ class Upload extends Base
     //上传图片
     //上传图片
     public function uploadImg()
     public function uploadImg()
     {
     {
-        $file = request()->file('file');
+        // 验证token.
+        $tokenStatus = $this->verifyToken();
+        $code        = -2;
+        $msg         = '错误';
+        if ($tokenStatus === false) {
+            $msg = 'token错误';
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }
 
 
-        $fileInfo = $file->getInfo();
-        /*if($fileInfo['size'] > 1024 * 1024 * 2){
-            // 上传失败获取错误信息
-            return json( ['code' => -2, 'data' => '', 'msg' => '文件超过2M'] );
-        }*/
+        try {
+            $file = request()->file('file');
 
 
-        //检测图片格式
-        $ext = explode('.', $fileInfo['name']);
-        $ext = array_pop($ext);
+            $fileInfo = $file->getInfo();
+            /*if($fileInfo['size'] > 1024 * 1024 * 2){
+                // 上传失败获取错误信息
+                return json( ['code' => -2, 'data' => '', 'msg' => '文件超过2M'] );
+            }*/
 
 
-        $extArr = explode('|', 'jpg|png|gif|jpeg');
-        if(!in_array($ext, $extArr)){
-            return json(['code' => -3, 'data' => '', 'msg' => '只能上传jpg|png|gif|jpeg的文件']);
-        }
+            //检测图片格式
+            $ext = explode('.', $fileInfo['name']);
+            $ext = array_pop($ext);
 
 
-        // 移动到框架应用根目录/public/uploads/ 目录下
-        $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
-        if($info){
-            $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
-            return json(['code' => 0, 'data' => ['src' => $src ], 'msg' => '']);
-        }else{
-            // 上传失败获取错误信息
-            return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
-        }
+            $extArr = explode('|', 'jpg|png|gif|jpeg');
+            if(!in_array($ext, $extArr)){
+                return json(['code' => -3, 'data' => '', 'msg' => '只能上传jpg|png|gif|jpeg的文件']);
+            }
+
+            // 移动到框架应用根目录/public/uploads/ 目录下
+            $info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
+            if($info){
+                $src =  '/uploads' . '/' . date('Ymd') . '/' . $info->getFilename();
+                return json(['code' => 0, 'data' => ['src' => $src ], 'msg' => '']);
+            }else{
+                // 上传失败获取错误信息
+                return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
+            }
+        } catch (\Exception $e) {
+            return json(['code' => $code, 'data' => [], 'msg' => $msg]);
+        }//end try
     }
     }
 
 
     //上传文件
     //上传文件
@@ -65,4 +78,4 @@ class Upload extends Base
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
             return json(['code' => -1, 'data' => '', 'msg' => $file->getError()]);
         }
         }
     }
     }
-}
+}

+ 21 - 21
application/service/controller/Words.php

@@ -21,6 +21,7 @@ class Words extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -38,7 +39,7 @@ class Words extends Common
             // 查询用户私有快捷语.
             // 查询用户私有快捷语.
             $userWords = model('words')->selectWords($wordsField, $userWordsWhere);
             $userWords = model('words')->selectWords($wordsField, $userWordsWhere);
 
 
-            return json(['code' => 200, 'data' => $userWords, 'msg' => '成功']);
+            return json(['code' => 1, 'data' => $userWords, 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -59,6 +60,7 @@ class Words extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
@@ -95,7 +97,7 @@ class Words extends Common
 
 
             // 参数返回.
             // 参数返回.
             if (isset($result) === true) {
             if (isset($result) === true) {
-                return json(['code' => 200, 'data' => [], 'msg' => '成功']);
+                return json(['code' => 1, 'data' => [], 'msg' => '成功']);
             } else {
             } else {
                 return json(['code' => 1, 'data' => [], 'msg' => 1]);
                 return json(['code' => 1, 'data' => [], 'msg' => 1]);
             }
             }
@@ -119,24 +121,21 @@ class Words extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
         try {
         try {
             // 获取用户信息.
             // 获取用户信息.
-            $getUserInfo    = $this->getUserInfo();
-            $userWordsWhere = [
-                'user_id' => $getUserInfo->id,
-                'id'      => input('post.id'),
-            ];
-            $deleteResult   = model('Words')->deleteWords($userWordsWhere);
+            $getUserInfo               = $this->getUserInfo();
+            $userWordsWhere['user_id'] = $getUserInfo->id;
+            foreach (input('post.') as $v) {
+                $userWordsWhere['id'] = $v;
+                model('Words')->deleteWords($userWordsWhere);
+            }
 
 
             // 参数返回.
             // 参数返回.
-            if (empty($deleteResult) === false) {
-                return json(['code' => 200, 'data' => [], 'msg' => '成功']);
-            } else {
-                return json(['code' => 1, 'data' => [], 'msg' => 1]);
-            }
+            return json(['code' => 1, 'data' => [], 'msg' => '成功']);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }//end try
         }//end try
@@ -157,24 +156,25 @@ class Words extends Common
         $code        = -2;
         $code        = -2;
         $msg         = '错误';
         $msg         = '错误';
         if ($tokenStatus === false) {
         if ($tokenStatus === false) {
+            $msg = 'token错误';
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
             return json(['code' => $code, 'data' => [], 'msg' => $msg]);
         }
         }
 
 
         try {
         try {
             // 获取用户信息.
             // 获取用户信息.
-            $getUserInfo    = $this->getUserInfo();
+            $getUserInfo   = $this->getUserInfo();
             $userWordsData = [
             $userWordsData = [
-                'user_id' => $getUserInfo->id,
-                'title'      => input('post.title'),
-                'content'      => input('post.content'),
-                'status'      => input('post.status'),
-                'add_time'      => date('Y-m-d H:i:s'),
+                'user_id'  => $getUserInfo->id,
+                'title'    => input('post.title'),
+                'content'  => input('post.content'),
+                'status'   => input('post.status'),
+                'add_time' => date('Y-m-d H:i:s'),
             ];
             ];
-            $deleteResult   = model('Words')->addWords($userWordsData);
+            $deleteResult  = model('Words')->addWords($userWordsData);
 
 
             // 参数返回.
             // 参数返回.
             if (empty($deleteResult) === false) {
             if (empty($deleteResult) === false) {
-                return json(['code' => 200, 'data' => [], 'msg' => '成功']);
+                return json(['code' => 1, 'data' => [], 'msg' => '成功']);
             } else {
             } else {
                 return json(['code' => 1, 'data' => [], 'msg' => 1]);
                 return json(['code' => 1, 'data' => [], 'msg' => 1]);
             }
             }

+ 11 - 0
composer.json

@@ -20,10 +20,21 @@
         "topthink/framework": "~5.0.0",
         "topthink/framework": "~5.0.0",
         "zoujingli/ip2region": "^1.0"
         "zoujingli/ip2region": "^1.0"
     },
     },
+    "autoload": {
+        "psr-4": {
+            "app\\": "application/"
+        }
+    },
     "extra": {
     "extra": {
         "think-path": "thinkphp"
         "think-path": "thinkphp"
     },
     },
     "config": {
     "config": {
         "preferred-install": "dist"
         "preferred-install": "dist"
+    },
+    "repositories": {
+        "packagist": {
+            "type": "composer",
+            "url": "https://packagist.phpcomposer.com"
+        }
     }
     }
 }
 }

+ 1 - 1
public/static/service/js/whisper.js

@@ -17,7 +17,7 @@ socket.onopen = function (res) {
         });
         });
     });
     });
     // 登录
     // 登录
-    var login_data = '{"type":"init", "uid":"' + uinfo.id + '", "name" : "' + uinfo.username + '", "avatar" : "'
+    var login_data = '{"type":"init", "uid":"' + uinfo.id + '", "token":"NzQ1MTM5IyRAJSFeKi8xNTYyMjkxMTczLzg=", "name" : "' + uinfo.username + '", "avatar" : "'
         + uinfo.avatar + '", "group": ' + uinfo.group + '}';
         + uinfo.avatar + '", "group": ' + uinfo.group + '}';
     socket.send(login_data);
     socket.send(login_data);
 };
 };

+ 2 - 2
thinkphp/CONTRIBUTING.md

@@ -7,7 +7,7 @@
 
 
 ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
 ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
 
 
-参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
+参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
 
 
 我们希望你贡献的代码符合:
 我们希望你贡献的代码符合:
 
 
@@ -60,7 +60,7 @@ GitHub 提供了 Issue 功能,该功能可以用于:
 6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
 6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
 7. `push` 你的本地仓库到 GitHub;
 7. `push` 你的本地仓库到 GitHub;
 8. 提交 `pull request`;
 8. 提交 `pull request`;
-9. 等待 CI 验证(若不通过则重复 5~7,GitHub 会自动更新你的 `pull request`);
+9. 等待 CI 验证(若不通过则重复 5~7,不需要重新提交 `pull request`,GitHub 会自动更新你的 `pull request`);
 10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
 10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
 
 
 *若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*
 *若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*

+ 1 - 1
thinkphp/LICENSE.txt

@@ -1,6 +1,6 @@
 
 
 ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
 ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
-版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+版权所有Copyright © 2006-2017 by ThinkPHP (http://thinkphp.cn)
 All rights reserved。
 All rights reserved。
 ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
 ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
 
 

+ 2 - 2
thinkphp/README.md

@@ -92,7 +92,7 @@ www  WEB部署目录(或者子目录)
 
 
 ## 命名规范
 ## 命名规范
 
 
-ThinkPHP5的命名规范遵循PSR-2规范以及PSR-4自动加载规范。
+ThinkPHP5的命名规范遵循`PSR-2`规范以及`PSR-4`自动加载规范。
 
 
 ## 参与开发
 ## 参与开发
 注册并登录 Github 帐号, fork 本项目并进行改动。
 注册并登录 Github 帐号, fork 本项目并进行改动。
@@ -105,7 +105,7 @@ ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
 
 
 本项目包含的第三方源码和二进制文件之版权信息另行标注。
 本项目包含的第三方源码和二进制文件之版权信息另行标注。
 
 
-版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn)
 
 
 All rights reserved。
 All rights reserved。
 
 

+ 4 - 2
thinkphp/base.php

@@ -2,14 +2,14 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Author: liu21st <liu21st@gmail.com>
 // | Author: liu21st <liu21st@gmail.com>
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 
 
-define('THINK_VERSION', '5.0.11');
+define('THINK_VERSION', '5.0.24');
 define('THINK_START_TIME', microtime(true));
 define('THINK_START_TIME', microtime(true));
 define('THINK_START_MEM', memory_get_usage());
 define('THINK_START_MEM', memory_get_usage());
 define('EXT', '.php');
 define('EXT', '.php');
@@ -40,8 +40,10 @@ require CORE_PATH . 'Loader.php';
 // 加载环境变量配置文件
 // 加载环境变量配置文件
 if (is_file(ROOT_PATH . '.env')) {
 if (is_file(ROOT_PATH . '.env')) {
     $env = parse_ini_file(ROOT_PATH . '.env', true);
     $env = parse_ini_file(ROOT_PATH . '.env', true);
+
     foreach ($env as $key => $val) {
     foreach ($env as $key => $val) {
         $name = ENV_PREFIX . strtoupper($key);
         $name = ENV_PREFIX . strtoupper($key);
+
         if (is_array($val)) {
         if (is_array($val)) {
             foreach ($val as $k => $v) {
             foreach ($val as $k => $v) {
                 $item = $name . '_' . strtoupper($k);
                 $item = $name . '_' . strtoupper($k);

+ 9 - 0
thinkphp/convention.php

@@ -116,6 +116,8 @@ return [
     // +----------------------------------------------------------------------
     // +----------------------------------------------------------------------
 
 
     'template'               => [
     'template'               => [
+        // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写
+        'auto_rule'    => 1,
         // 模板引擎类型 支持 php think 支持扩展
         // 模板引擎类型 支持 php think 支持扩展
         'type'         => 'Think',
         'type'         => 'Think',
         // 视图基础目录,配置目录为所有模块的视图起始目录
         // 视图基础目录,配置目录为所有模块的视图起始目录
@@ -286,4 +288,11 @@ return [
         'list_rows' => 15,
         'list_rows' => 15,
     ],
     ],
 
 
+    //控制台配置
+    'console'                => [
+        'name'    => 'Think Console',
+        'version' => '0.1',
+        'user'    => null,
+    ],
+
 ];
 ];

+ 1 - 1
thinkphp/helper.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 120 - 53
thinkphp/lang/zh-cn.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -12,58 +12,125 @@
 // 核心中文语言包
 // 核心中文语言包
 return [
 return [
     // 系统错误提示
     // 系统错误提示
-    'Undefined variable'        => '未定义变量',
-    'Undefined index'           => '未定义数组索引',
-    'Undefined offset'          => '未定义数组下标',
-    'Parse error'               => '语法解析错误',
-    'Type error'                => '类型错误',
-    'Fatal error'               => '致命错误',
-    'syntax error'              => '语法错误',
+    'Undefined variable'                                        => '未定义变量',
+    'Undefined index'                                           => '未定义数组索引',
+    'Undefined offset'                                          => '未定义数组下标',
+    'Parse error'                                               => '语法解析错误',
+    'Type error'                                                => '类型错误',
+    'Fatal error'                                               => '致命错误',
+    'syntax error'                                              => '语法错误',
 
 
     // 框架核心错误提示
     // 框架核心错误提示
-    'dispatch type not support' => '不支持的调度类型',
-    'method param miss'         => '方法参数错误',
-    'method not exists'         => '方法不存在',
-    'module not exists'         => '模块不存在',
-    'controller not exists'     => '控制器不存在',
-    'class not exists'          => '类不存在',
-    'property not exists'       => '类的属性不存在',
-    'template not exists'       => '模板文件不存在',
-    'illegal controller name'   => '非法的控制器名称',
-    'illegal action name'       => '非法的操作名称',
-    'url suffix deny'           => '禁止的URL后缀访问',
-    'Route Not Found'           => '当前访问路由未定义',
-    'Undefined db type'         => '未定义数据库类型',
-    'variable type error'       => '变量类型错误',
-    'PSR-4 error'               => 'PSR-4 规范错误',
-    'not support total'         => '简洁模式下不能获取数据总数',
-    'not support last'          => '简洁模式下不能获取最后一页',
-    'error session handler'     => '错误的SESSION处理器类',
-    'not allow php tag'         => '模板不允许使用PHP语法',
-    'not support'               => '不支持',
-    'redisd master'             => 'Redisd 主服务器错误',
-    'redisd slave'              => 'Redisd 从服务器错误',
-    'must run at sae'           => '必须在SAE运行',
-    'memcache init error'       => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
-    'KVDB init error'           => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
-    'fields not exists'         => '数据表字段不存在',
-    'where express error'       => '查询表达式错误',
-    'no data to update'         => '没有任何数据需要更新',
-    'miss data to insert'       => '缺少需要写入的数据',
-    'miss complex primary data' => '缺少复合主键数据',
-    'miss update condition'     => '缺少更新条件',
-    'model data Not Found'      => '模型数据不存在',
-    'table data not Found'      => '表数据不存在',
-    'delete without condition'  => '没有条件不会执行删除操作',
-    'miss relation data'        => '缺少关联表数据',
-    'tag attr must'             => '模板标签属性必须',
-    'tag error'                 => '模板标签错误',
-    'cache write error'         => '缓存写入失败',
-    'sae mc write error'        => 'SAE mc 写入错误',
-    'route name not exists'     => '路由标识不存在(或参数不够)',
-    'invalid request'           => '非法请求',
-    'bind attr has exists'      => '模型的属性已经存在',
-    'relation data not exists'  => '关联数据不存在',
-    'relation not support'      => '关联不支持',
-    'chunk not support order'   => 'Chunk不支持调用order方法',
+    'dispatch type not support'                                 => '不支持的调度类型',
+    'method param miss'                                         => '方法参数错误',
+    'method not exists'                                         => '方法不存在',
+    'module not exists'                                         => '模块不存在',
+    'controller not exists'                                     => '控制器不存在',
+    'class not exists'                                          => '类不存在',
+    'property not exists'                                       => '类的属性不存在',
+    'template not exists'                                       => '模板文件不存在',
+    'illegal controller name'                                   => '非法的控制器名称',
+    'illegal action name'                                       => '非法的操作名称',
+    'url suffix deny'                                           => '禁止的URL后缀访问',
+    'Route Not Found'                                           => '当前访问路由未定义',
+    'Undefined db type'                                         => '未定义数据库类型',
+    'variable type error'                                       => '变量类型错误',
+    'PSR-4 error'                                               => 'PSR-4 规范错误',
+    'not support total'                                         => '简洁模式下不能获取数据总数',
+    'not support last'                                          => '简洁模式下不能获取最后一页',
+    'error session handler'                                     => '错误的SESSION处理器类',
+    'not allow php tag'                                         => '模板不允许使用PHP语法',
+    'not support'                                               => '不支持',
+    'redisd master'                                             => 'Redisd 主服务器错误',
+    'redisd slave'                                              => 'Redisd 从服务器错误',
+    'must run at sae'                                           => '必须在SAE运行',
+    'memcache init error'                                       => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
+    'KVDB init error'                                           => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
+    'fields not exists'                                         => '数据表字段不存在',
+    'where express error'                                       => '查询表达式错误',
+    'not support data'                                          => '不支持的数据表达式',
+    'no data to update'                                         => '没有任何数据需要更新',
+    'miss data to insert'                                       => '缺少需要写入的数据',
+    'miss complex primary data'                                 => '缺少复合主键数据',
+    'miss update condition'                                     => '缺少更新条件',
+    'model data Not Found'                                      => '模型数据不存在',
+    'table data not Found'                                      => '表数据不存在',
+    'delete without condition'                                  => '没有条件不会执行删除操作',
+    'miss relation data'                                        => '缺少关联表数据',
+    'tag attr must'                                             => '模板标签属性必须',
+    'tag error'                                                 => '模板标签错误',
+    'cache write error'                                         => '缓存写入失败',
+    'sae mc write error'                                        => 'SAE mc 写入错误',
+    'route name not exists'                                     => '路由标识不存在(或参数不够)',
+    'invalid request'                                           => '非法请求',
+    'bind attr has exists'                                      => '模型的属性已经存在',
+    'relation data not exists'                                  => '关联数据不存在',
+    'relation not support'                                      => '关联不支持',
+    'chunk not support order'                                   => 'Chunk不支持调用order方法',
+    'closure not support cache(true)'                           => '使用闭包查询不支持cache(true),请指定缓存Key',
+
+    // 上传错误信息
+    'unknown upload error'                                      => '未知上传错误!',
+    'file write error'                                          => '文件写入失败!',
+    'upload temp dir not found'                                 => '找不到临时文件夹!',
+    'no file to uploaded'                                       => '没有文件被上传!',
+    'only the portion of file is uploaded'                      => '文件只有部分被上传!',
+    'upload File size exceeds the maximum value'                => '上传文件大小超过了最大值!',
+    'upload write error'                                        => '文件上传保存错误!',
+    'has the same filename: {:filename}'                        => '存在同名文件:{:filename}',
+    'upload illegal files'                                      => '非法上传文件',
+    'illegal image files'                                       => '非法图片文件',
+    'extensions to upload is not allowed'                       => '上传文件后缀不允许',
+    'mimetype to upload is not allowed'                         => '上传文件MIME类型不允许!',
+    'filesize not match'                                        => '上传文件大小不符!',
+    'directory {:path} creation failed'                         => '目录 {:path} 创建失败!',
+
+    // Validate Error Message
+    ':attribute require'                                        => ':attribute不能为空',
+    ':attribute must be numeric'                                => ':attribute必须是数字',
+    ':attribute must be integer'                                => ':attribute必须是整数',
+    ':attribute must be float'                                  => ':attribute必须是浮点数',
+    ':attribute must be bool'                                   => ':attribute必须是布尔值',
+    ':attribute not a valid email address'                      => ':attribute格式不符',
+    ':attribute not a valid mobile'                             => ':attribute格式不符',
+    ':attribute must be a array'                                => ':attribute必须是数组',
+    ':attribute must be yes,on or 1'                            => ':attribute必须是yes、on或者1',
+    ':attribute not a valid datetime'                           => ':attribute不是一个有效的日期或时间格式',
+    ':attribute not a valid file'                               => ':attribute不是有效的上传文件',
+    ':attribute not a valid image'                              => ':attribute不是有效的图像文件',
+    ':attribute must be alpha'                                  => ':attribute只能是字母',
+    ':attribute must be alpha-numeric'                          => ':attribute只能是字母和数字',
+    ':attribute must be alpha-numeric, dash, underscore'        => ':attribute只能是字母、数字和下划线_及破折号-',
+    ':attribute not a valid domain or ip'                       => ':attribute不是有效的域名或者IP',
+    ':attribute must be chinese'                                => ':attribute只能是汉字',
+    ':attribute must be chinese or alpha'                       => ':attribute只能是汉字、字母',
+    ':attribute must be chinese,alpha-numeric'                  => ':attribute只能是汉字、字母和数字',
+    ':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
+    ':attribute not a valid url'                                => ':attribute不是有效的URL地址',
+    ':attribute not a valid ip'                                 => ':attribute不是有效的IP地址',
+    ':attribute must be dateFormat of :rule'                    => ':attribute必须使用日期格式 :rule',
+    ':attribute must be in :rule'                               => ':attribute必须在 :rule 范围内',
+    ':attribute be notin :rule'                                 => ':attribute不能在 :rule 范围内',
+    ':attribute must between :1 - :2'                           => ':attribute只能在 :1 - :2 之间',
+    ':attribute not between :1 - :2'                            => ':attribute不能在 :1 - :2 之间',
+    'size of :attribute must be :rule'                          => ':attribute长度不符合要求 :rule',
+    'max size of :attribute must be :rule'                      => ':attribute长度不能超过 :rule',
+    'min size of :attribute must be :rule'                      => ':attribute长度不能小于 :rule',
+    ':attribute cannot be less than :rule'                      => ':attribute日期不能小于 :rule',
+    ':attribute cannot exceed :rule'                            => ':attribute日期不能超过 :rule',
+    ':attribute not within :rule'                               => '不在有效期内 :rule',
+    'access IP is not allowed'                                  => '不允许的IP访问',
+    'access IP denied'                                          => '禁止的IP访问',
+    ':attribute out of accord with :2'                          => ':attribute和确认字段:2不一致',
+    ':attribute cannot be same with :2'                         => ':attribute和比较字段:2不能相同',
+    ':attribute must greater than or equal :rule'               => ':attribute必须大于等于 :rule',
+    ':attribute must greater than :rule'                        => ':attribute必须大于 :rule',
+    ':attribute must less than or equal :rule'                  => ':attribute必须小于等于 :rule',
+    ':attribute must less than :rule'                           => ':attribute必须小于 :rule',
+    ':attribute must equal :rule'                               => ':attribute必须等于 :rule',
+    ':attribute has exists'                                     => ':attribute已存在',
+    ':attribute not conform to the rules'                       => ':attribute不符合指定规则',
+    'invalid Request method'                                    => '无效的请求类型',
+    'invalid token'                                             => '令牌数据无效',
+    'not conform to the rules'                                  => '规则错误',
 ];
 ];

+ 264 - 178
thinkphp/library/think/App.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -18,7 +18,7 @@ use think\exception\RouteNotFoundException;
 
 
 /**
 /**
  * App 应用管理
  * App 应用管理
- * @author  liu21st <liu21st@gmail.com>
+ * @author liu21st <liu21st@gmail.com>
  */
  */
 class App
 class App
 {
 {
@@ -57,24 +57,32 @@ class App
      */
      */
     protected static $routeMust;
     protected static $routeMust;
 
 
+    /**
+     * @var array 请求调度分发
+     */
     protected static $dispatch;
     protected static $dispatch;
+
+    /**
+     * @var array 额外加载文件
+     */
     protected static $file = [];
     protected static $file = [];
 
 
     /**
     /**
      * 执行应用程序
      * 执行应用程序
      * @access public
      * @access public
-     * @param Request $request Request对象
+     * @param  Request $request 请求对象
      * @return Response
      * @return Response
      * @throws Exception
      * @throws Exception
      */
      */
     public static function run(Request $request = null)
     public static function run(Request $request = null)
     {
     {
-        is_null($request) && $request = Request::instance();
+        $request = is_null($request) ? Request::instance() : $request;
 
 
         try {
         try {
             $config = self::initCommon();
             $config = self::initCommon();
+
+            // 模块/控制器绑定
             if (defined('BIND_MODULE')) {
             if (defined('BIND_MODULE')) {
-                // 模块/控制器绑定
                 BIND_MODULE && Route::bind(BIND_MODULE);
                 BIND_MODULE && Route::bind(BIND_MODULE);
             } elseif ($config['auto_bind_module']) {
             } elseif ($config['auto_bind_module']) {
                 // 入口自动绑定
                 // 入口自动绑定
@@ -88,10 +96,8 @@ class App
 
 
             // 默认语言
             // 默认语言
             Lang::range($config['default_lang']);
             Lang::range($config['default_lang']);
-            if ($config['lang_switch_on']) {
-                // 开启多语言机制 检测当前语言
-                Lang::detect();
-            }
+            // 开启多语言机制 检测当前语言
+            $config['lang_switch_on'] && Lang::detect();
             $request->langset(Lang::range());
             $request->langset(Lang::range());
 
 
             // 加载系统语言包
             // 加载系统语言包
@@ -100,12 +106,16 @@ class App
                 APP_PATH . 'lang' . DS . $request->langset() . EXT,
                 APP_PATH . 'lang' . DS . $request->langset() . EXT,
             ]);
             ]);
 
 
+            // 监听 app_dispatch
+            Hook::listen('app_dispatch', self::$dispatch);
             // 获取应用调度信息
             // 获取应用调度信息
             $dispatch = self::$dispatch;
             $dispatch = self::$dispatch;
+
+            // 未设置调度信息则进行 URL 路由检测
             if (empty($dispatch)) {
             if (empty($dispatch)) {
-                // 进行URL路由检测
                 $dispatch = self::routeCheck($request, $config);
                 $dispatch = self::routeCheck($request, $config);
             }
             }
+
             // 记录当前调度信息
             // 记录当前调度信息
             $request->dispatch($dispatch);
             $request->dispatch($dispatch);
 
 
@@ -116,10 +126,15 @@ class App
                 Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
                 Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
             }
             }
 
 
-            // 监听app_begin
+            // 监听 app_begin
             Hook::listen('app_begin', $dispatch);
             Hook::listen('app_begin', $dispatch);
+
             // 请求缓存检查
             // 请求缓存检查
-            $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);
+            $request->cache(
+                $config['request_cache'],
+                $config['request_cache_expire'],
+                $config['request_cache_except']
+            );
 
 
             $data = self::exec($dispatch, $config);
             $data = self::exec($dispatch, $config);
         } catch (HttpResponseException $exception) {
         } catch (HttpResponseException $exception) {
@@ -134,24 +149,151 @@ class App
             $response = $data;
             $response = $data;
         } elseif (!is_null($data)) {
         } elseif (!is_null($data)) {
             // 默认自动识别响应输出类型
             // 默认自动识别响应输出类型
-            $isAjax   = $request->isAjax();
-            $type     = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');
+            $type = $request->isAjax() ?
+            Config::get('default_ajax_return') :
+            Config::get('default_return_type');
+
             $response = Response::create($data, $type);
             $response = Response::create($data, $type);
         } else {
         } else {
             $response = Response::create();
             $response = Response::create();
         }
         }
 
 
-        // 监听app_end
+        // 监听 app_end
         Hook::listen('app_end', $response);
         Hook::listen('app_end', $response);
 
 
         return $response;
         return $response;
     }
     }
 
 
+    /**
+     * 初始化应用,并返回配置信息
+     * @access public
+     * @return array
+     */
+    public static function initCommon()
+    {
+        if (empty(self::$init)) {
+            if (defined('APP_NAMESPACE')) {
+                self::$namespace = APP_NAMESPACE;
+            }
+
+            Loader::addNamespace(self::$namespace, APP_PATH);
+
+            // 初始化应用
+            $config       = self::init();
+            self::$suffix = $config['class_suffix'];
+
+            // 应用调试模式
+            self::$debug = Env::get('app_debug', Config::get('app_debug'));
+
+            if (!self::$debug) {
+                ini_set('display_errors', 'Off');
+            } elseif (!IS_CLI) {
+                // 重新申请一块比较大的 buffer
+                if (ob_get_level() > 0) {
+                    $output = ob_get_clean();
+                }
+
+                ob_start();
+
+                if (!empty($output)) {
+                    echo $output;
+                }
+
+            }
+
+            if (!empty($config['root_namespace'])) {
+                Loader::addNamespace($config['root_namespace']);
+            }
+
+            // 加载额外文件
+            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) && !isset(self::$file[$file])) {
+                        include $file;
+                        self::$file[$file] = true;
+                    }
+                }
+            }
+
+            // 设置系统时区
+            date_default_timezone_set($config['default_timezone']);
+
+            // 监听 app_init
+            Hook::listen('app_init');
+
+            self::$init = true;
+        }
+
+        return Config::get();
+    }
+
+    /**
+     * 初始化应用或模块
+     * @access public
+     * @param string $module 模块名
+     * @return array
+     */
+    private static function init($module = '')
+    {
+        // 定位模块目录
+        $module = $module ? $module . DS : '';
+
+        // 加载初始化文件
+        if (is_file(APP_PATH . $module . 'init' . EXT)) {
+            include APP_PATH . $module . 'init' . EXT;
+        } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
+            include RUNTIME_PATH . $module . 'init' . EXT;
+        } else {
+            // 加载模块配置
+            $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
+
+            // 读取数据库配置文件
+            $filename = CONF_PATH . $module . 'database' . CONF_EXT;
+            Config::load($filename, 'database');
+
+            // 读取扩展配置文件
+            if (is_dir(CONF_PATH . $module . 'extra')) {
+                $dir   = CONF_PATH . $module . 'extra';
+                $files = scandir($dir);
+                foreach ($files as $file) {
+                    if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
+                        $filename = $dir . DS . $file;
+                        Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
+                    }
+                }
+            }
+
+            // 加载应用状态配置
+            if ($config['app_status']) {
+                Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
+            }
+
+            // 加载行为扩展文件
+            if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
+                Hook::import(include CONF_PATH . $module . 'tags' . EXT);
+            }
+
+            // 加载公共文件
+            $path = APP_PATH . $module;
+            if (is_file($path . 'common' . EXT)) {
+                include $path . 'common' . EXT;
+            }
+
+            // 加载当前模块语言包
+            if ($module) {
+                Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
+            }
+        }
+
+        return Config::get();
+    }
+
     /**
     /**
      * 设置当前请求的调度信息
      * 设置当前请求的调度信息
      * @access public
      * @access public
      * @param array|string  $dispatch 调度信息
      * @param array|string  $dispatch 调度信息
-     * @param string        $type 调度类型
+     * @param string        $type     调度类型
      * @return void
      * @return void
      */
      */
     public static function dispatch($dispatch, $type = 'module')
     public static function dispatch($dispatch, $type = 'module')
@@ -170,8 +312,10 @@ class App
     {
     {
         $reflect = new \ReflectionFunction($function);
         $reflect = new \ReflectionFunction($function);
         $args    = self::bindParams($reflect, $vars);
         $args    = self::bindParams($reflect, $vars);
+
         // 记录执行信息
         // 记录执行信息
         self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
         self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
+
         return $reflect->invokeArgs($args);
         return $reflect->invokeArgs($args);
     }
     }
 
 
@@ -191,28 +335,27 @@ class App
             // 静态方法
             // 静态方法
             $reflect = new \ReflectionMethod($method);
             $reflect = new \ReflectionMethod($method);
         }
         }
+
         $args = self::bindParams($reflect, $vars);
         $args = self::bindParams($reflect, $vars);
 
 
         self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
         self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
+
         return $reflect->invokeArgs(isset($class) ? $class : null, $args);
         return $reflect->invokeArgs(isset($class) ? $class : null, $args);
     }
     }
 
 
     /**
     /**
      * 调用反射执行类的实例化 支持依赖注入
      * 调用反射执行类的实例化 支持依赖注入
      * @access public
      * @access public
-     * @param string    $class 类名
-     * @param array     $vars  变量
+     * @param string $class 类名
+     * @param array  $vars  变量
      * @return mixed
      * @return mixed
      */
      */
     public static function invokeClass($class, $vars = [])
     public static function invokeClass($class, $vars = [])
     {
     {
         $reflect     = new \ReflectionClass($class);
         $reflect     = new \ReflectionClass($class);
         $constructor = $reflect->getConstructor();
         $constructor = $reflect->getConstructor();
-        if ($constructor) {
-            $args = self::bindParams($constructor, $vars);
-        } else {
-            $args = [];
-        }
+        $args        = $constructor ? self::bindParams($constructor, $vars) : [];
+
         return $reflect->newInstanceArgs($args);
         return $reflect->newInstanceArgs($args);
     }
     }
 
 
@@ -225,52 +368,58 @@ class App
      */
      */
     private static function bindParams($reflect, $vars = [])
     private static function bindParams($reflect, $vars = [])
     {
     {
+        // 自动获取请求变量
         if (empty($vars)) {
         if (empty($vars)) {
-            // 自动获取请求变量
-            if (Config::get('url_param_type')) {
-                $vars = Request::instance()->route();
-            } else {
-                $vars = Request::instance()->param();
-            }
+            $vars = Config::get('url_param_type') ?
+            Request::instance()->route() :
+            Request::instance()->param();
         }
         }
+
         $args = [];
         $args = [];
         if ($reflect->getNumberOfParameters() > 0) {
         if ($reflect->getNumberOfParameters() > 0) {
             // 判断数组类型 数字数组时按顺序绑定参数
             // 判断数组类型 数字数组时按顺序绑定参数
             reset($vars);
             reset($vars);
-            $type   = key($vars) === 0 ? 1 : 0;
-            $params = $reflect->getParameters();
-            foreach ($params as $param) {
+            $type = key($vars) === 0 ? 1 : 0;
+
+            foreach ($reflect->getParameters() as $param) {
                 $args[] = self::getParamValue($param, $vars, $type);
                 $args[] = self::getParamValue($param, $vars, $type);
             }
             }
         }
         }
+
         return $args;
         return $args;
     }
     }
 
 
     /**
     /**
      * 获取参数值
      * 获取参数值
      * @access private
      * @access private
-     * @param \ReflectionParameter  $param
-     * @param array                 $vars    变量
-     * @param string                $type
+     * @param \ReflectionParameter  $param 参数
+     * @param array                 $vars  变量
+     * @param string                $type  类别
      * @return array
      * @return array
      */
      */
     private static function getParamValue($param, &$vars, $type)
     private static function getParamValue($param, &$vars, $type)
     {
     {
         $name  = $param->getName();
         $name  = $param->getName();
         $class = $param->getClass();
         $class = $param->getClass();
+
         if ($class) {
         if ($class) {
             $className = $class->getName();
             $className = $class->getName();
             $bind      = Request::instance()->$name;
             $bind      = Request::instance()->$name;
+
             if ($bind instanceof $className) {
             if ($bind instanceof $className) {
                 $result = $bind;
                 $result = $bind;
             } else {
             } else {
                 if (method_exists($className, 'invoke')) {
                 if (method_exists($className, 'invoke')) {
                     $method = new \ReflectionMethod($className, 'invoke');
                     $method = new \ReflectionMethod($className, 'invoke');
+
                     if ($method->isPublic() && $method->isStatic()) {
                     if ($method->isPublic() && $method->isStatic()) {
                         return $className::invoke(Request::instance());
                         return $className::invoke(Request::instance());
                     }
                     }
                 }
                 }
-                $result = method_exists($className, 'instance') ? $className::instance() : new $className;
+
+                $result = method_exists($className, 'instance') ?
+                $className::instance() :
+                new $className;
             }
             }
         } elseif (1 == $type && !empty($vars)) {
         } elseif (1 == $type && !empty($vars)) {
             $result = array_shift($vars);
             $result = array_shift($vars);
@@ -281,65 +430,85 @@ class App
         } else {
         } else {
             throw new \InvalidArgumentException('method param miss:' . $name);
             throw new \InvalidArgumentException('method param miss:' . $name);
         }
         }
+
         return $result;
         return $result;
     }
     }
 
 
+    /**
+     * 执行调用分发
+     * @access protected
+     * @param array $dispatch 调用信息
+     * @param array $config   配置信息
+     * @return Response|mixed
+     * @throws \InvalidArgumentException
+     */
     protected static function exec($dispatch, $config)
     protected static function exec($dispatch, $config)
     {
     {
         switch ($dispatch['type']) {
         switch ($dispatch['type']) {
-            case 'redirect':
-                // 执行重定向跳转
-                $data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']);
+            case 'redirect': // 重定向跳转
+                $data = Response::create($dispatch['url'], 'redirect')
+                    ->code($dispatch['status']);
                 break;
                 break;
-            case 'module':
-                // 模块/控制器/操作
-                $data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null);
+            case 'module': // 模块/控制器/操作
+                $data = self::module(
+                    $dispatch['module'],
+                    $config,
+                    isset($dispatch['convert']) ? $dispatch['convert'] : null
+                );
                 break;
                 break;
-            case 'controller':
-                // 执行控制器操作
+            case 'controller': // 执行控制器操作
                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
-                $data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']);
+                $data = Loader::action(
+                    $dispatch['controller'],
+                    $vars,
+                    $config['url_controller_layer'],
+                    $config['controller_suffix']
+                );
                 break;
                 break;
-            case 'method':
-                // 执行回调方法
+            case 'method': // 回调方法
                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
                 $vars = array_merge(Request::instance()->param(), $dispatch['var']);
                 $data = self::invokeMethod($dispatch['method'], $vars);
                 $data = self::invokeMethod($dispatch['method'], $vars);
                 break;
                 break;
-            case 'function':
-                // 执行闭包
+            case 'function': // 闭包
                 $data = self::invokeFunction($dispatch['function']);
                 $data = self::invokeFunction($dispatch['function']);
                 break;
                 break;
-            case 'response':
+            case 'response': // Response 实例
                 $data = $dispatch['response'];
                 $data = $dispatch['response'];
                 break;
                 break;
             default:
             default:
                 throw new \InvalidArgumentException('dispatch type not support');
                 throw new \InvalidArgumentException('dispatch type not support');
         }
         }
+
         return $data;
         return $data;
     }
     }
 
 
     /**
     /**
      * 执行模块
      * 执行模块
      * @access public
      * @access public
-     * @param array $result 模块/控制器/操作
-     * @param array $config 配置参数
+     * @param array $result  模块/控制器/操作
+     * @param array $config  配置参数
      * @param bool  $convert 是否自动转换控制器和操作名
      * @param bool  $convert 是否自动转换控制器和操作名
      * @return mixed
      * @return mixed
+     * @throws HttpException
      */
      */
     public static function module($result, $config, $convert = null)
     public static function module($result, $config, $convert = null)
     {
     {
         if (is_string($result)) {
         if (is_string($result)) {
             $result = explode('/', $result);
             $result = explode('/', $result);
         }
         }
+
         $request = Request::instance();
         $request = Request::instance();
+
         if ($config['app_multi_module']) {
         if ($config['app_multi_module']) {
             // 多模块部署
             // 多模块部署
             $module    = strip_tags(strtolower($result[0] ?: $config['default_module']));
             $module    = strip_tags(strtolower($result[0] ?: $config['default_module']));
             $bind      = Route::getBind('module');
             $bind      = Route::getBind('module');
             $available = false;
             $available = false;
+
             if ($bind) {
             if ($bind) {
                 // 绑定模块
                 // 绑定模块
                 list($bindModule) = explode('/', $bind);
                 list($bindModule) = explode('/', $bind);
+
                 if (empty($result[0])) {
                 if (empty($result[0])) {
                     $module    = $bindModule;
                     $module    = $bindModule;
                     $available = true;
                     $available = true;
@@ -355,8 +524,13 @@ class App
                 // 初始化模块
                 // 初始化模块
                 $request->module($module);
                 $request->module($module);
                 $config = self::init($module);
                 $config = self::init($module);
+
                 // 模块请求缓存检查
                 // 模块请求缓存检查
-                $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);
+                $request->cache(
+                    $config['request_cache'],
+                    $config['request_cache_expire'],
+                    $config['request_cache_except']
+                );
             } else {
             } else {
                 throw new HttpException(404, 'module not exists:' . $module);
                 throw new HttpException(404, 'module not exists:' . $module);
             }
             }
@@ -365,18 +539,32 @@ class App
             $module = '';
             $module = '';
             $request->module($module);
             $request->module($module);
         }
         }
+
+        // 设置默认过滤机制
+        $request->filter($config['default_filter']);
+
         // 当前模块路径
         // 当前模块路径
         App::$modulePath = APP_PATH . ($module ? $module . DS : '');
         App::$modulePath = APP_PATH . ($module ? $module . DS : '');
 
 
         // 是否自动转换控制器和操作名
         // 是否自动转换控制器和操作名
         $convert = is_bool($convert) ? $convert : $config['url_convert'];
         $convert = is_bool($convert) ? $convert : $config['url_convert'];
+
         // 获取控制器名
         // 获取控制器名
         $controller = strip_tags($result[1] ?: $config['default_controller']);
         $controller = strip_tags($result[1] ?: $config['default_controller']);
+
+        if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
+            throw new HttpException(404, 'controller not exists:' . $controller);
+        }
+
         $controller = $convert ? strtolower($controller) : $controller;
         $controller = $convert ? strtolower($controller) : $controller;
 
 
         // 获取操作名
         // 获取操作名
         $actionName = strip_tags($result[2] ?: $config['default_action']);
         $actionName = strip_tags($result[2] ?: $config['default_action']);
-        $actionName = $convert ? strtolower($actionName) : $actionName;
+        if (!empty($config['action_convert'])) {
+            $actionName = Loader::parseName($actionName, 1);
+        } else {
+            $actionName = $convert ? strtolower($actionName) : $actionName;
+        }
 
 
         // 设置当前请求的控制器、操作
         // 设置当前请求的控制器、操作
         $request->controller(Loader::parseName($controller, 1))->action($actionName);
         $request->controller(Loader::parseName($controller, 1))->action($actionName);
@@ -385,7 +573,12 @@ class App
         Hook::listen('module_init', $request);
         Hook::listen('module_init', $request);
 
 
         try {
         try {
-            $instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']);
+            $instance = Loader::controller(
+                $controller,
+                $config['url_controller_layer'],
+                $config['controller_suffix'],
+                $config['empty_controller']
+            );
         } catch (ClassNotFoundException $e) {
         } catch (ClassNotFoundException $e) {
             throw new HttpException(404, 'controller not exists:' . $e->getClass());
             throw new HttpException(404, 'controller not exists:' . $e->getClass());
         }
         }
@@ -397,6 +590,13 @@ class App
         if (is_callable([$instance, $action])) {
         if (is_callable([$instance, $action])) {
             // 执行操作方法
             // 执行操作方法
             $call = [$instance, $action];
             $call = [$instance, $action];
+            // 严格获取当前操作方法名
+            $reflect    = new \ReflectionMethod($instance, $action);
+            $methodName = $reflect->getName();
+            $suffix     = $config['action_suffix'];
+            $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
+            $request->action($actionName);
+
         } elseif (is_callable([$instance, '_empty'])) {
         } elseif (is_callable([$instance, '_empty'])) {
             // 空操作
             // 空操作
             $call = [$instance, '_empty'];
             $call = [$instance, '_empty'];
@@ -411,125 +611,11 @@ class App
         return self::invokeMethod($call, $vars);
         return self::invokeMethod($call, $vars);
     }
     }
 
 
-    /**
-     * 初始化应用
-     */
-    public static function initCommon()
-    {
-        if (empty(self::$init)) {
-            if (defined('APP_NAMESPACE')) {
-                self::$namespace = APP_NAMESPACE;
-            }
-            Loader::addNamespace(self::$namespace, APP_PATH);
-
-            // 初始化应用
-            $config       = self::init();
-            self::$suffix = $config['class_suffix'];
-
-            // 应用调试模式
-            self::$debug = Env::get('app_debug', Config::get('app_debug'));
-            if (!self::$debug) {
-                ini_set('display_errors', 'Off');
-            } elseif (!IS_CLI) {
-                //重新申请一块比较大的buffer
-                if (ob_get_level() > 0) {
-                    $output = ob_get_clean();
-                }
-                ob_start();
-                if (!empty($output)) {
-                    echo $output;
-                }
-            }
-
-            if (!empty($config['root_namespace'])) {
-                Loader::addNamespace($config['root_namespace']);
-            }
-
-            // 加载额外文件
-            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) && !isset(self::$file[$file])) {
-                        include $file;
-                        self::$file[$file] = true;
-                    }
-                }
-            }
-
-            // 设置系统时区
-            date_default_timezone_set($config['default_timezone']);
-
-            // 监听app_init
-            Hook::listen('app_init');
-
-            self::$init = true;
-        }
-        return Config::get();
-    }
-
-    /**
-     * 初始化应用或模块
-     * @access public
-     * @param string $module 模块名
-     * @return array
-     */
-    private static function init($module = '')
-    {
-        // 定位模块目录
-        $module = $module ? $module . DS : '';
-
-        // 加载初始化文件
-        if (is_file(APP_PATH . $module . 'init' . EXT)) {
-            include APP_PATH . $module . 'init' . EXT;
-        } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
-            include RUNTIME_PATH . $module . 'init' . EXT;
-        } else {
-            $path = APP_PATH . $module;
-            // 加载模块配置
-            $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
-            // 读取数据库配置文件
-            $filename = CONF_PATH . $module . 'database' . CONF_EXT;
-            Config::load($filename, 'database');
-            // 读取扩展配置文件
-            if (is_dir(CONF_PATH . $module . 'extra')) {
-                $dir   = CONF_PATH . $module . 'extra';
-                $files = scandir($dir);
-                foreach ($files as $file) {
-                    if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
-                        $filename = $dir . DS . $file;
-                        Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
-                    }
-                }
-            }
-
-            // 加载应用状态配置
-            if ($config['app_status']) {
-                $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
-            }
-
-            // 加载行为扩展文件
-            if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
-                Hook::import(include CONF_PATH . $module . 'tags' . EXT);
-            }
-
-            // 加载公共文件
-            if (is_file($path . 'common' . EXT)) {
-                include $path . 'common' . EXT;
-            }
-
-            // 加载当前模块语言包
-            if ($module) {
-                Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
-            }
-        }
-        return Config::get();
-    }
-
     /**
     /**
      * URL路由检测(根据PATH_INFO)
      * URL路由检测(根据PATH_INFO)
      * @access public
      * @access public
-     * @param  \think\Request $request
-     * @param  array          $config
+     * @param  \think\Request $request 请求实例
+     * @param  array          $config  配置信息
      * @return array
      * @return array
      * @throws \think\Exception
      * @throws \think\Exception
      */
      */
@@ -538,6 +624,7 @@ class App
         $path   = $request->path();
         $path   = $request->path();
         $depr   = $config['pathinfo_depr'];
         $depr   = $config['pathinfo_depr'];
         $result = false;
         $result = false;
+
         // 路由检测
         // 路由检测
         $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
         $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
         if ($check) {
         if ($check) {
@@ -545,18 +632,14 @@ class App
             if (is_file(RUNTIME_PATH . 'route.php')) {
             if (is_file(RUNTIME_PATH . 'route.php')) {
                 // 读取路由缓存
                 // 读取路由缓存
                 $rules = include RUNTIME_PATH . 'route.php';
                 $rules = include RUNTIME_PATH . 'route.php';
-                if (is_array($rules)) {
-                    Route::rules($rules);
-                }
+                is_array($rules) && Route::rules($rules);
             } else {
             } else {
                 $files = $config['route_config_file'];
                 $files = $config['route_config_file'];
                 foreach ($files as $file) {
                 foreach ($files as $file) {
                     if (is_file(CONF_PATH . $file . CONF_EXT)) {
                     if (is_file(CONF_PATH . $file . CONF_EXT)) {
                         // 导入路由配置
                         // 导入路由配置
                         $rules = include CONF_PATH . $file . CONF_EXT;
                         $rules = include CONF_PATH . $file . CONF_EXT;
-                        if (is_array($rules)) {
-                            Route::import($rules);
-                        }
+                        is_array($rules) && Route::import($rules);
                     }
                     }
                 }
                 }
             }
             }
@@ -564,15 +647,18 @@ class App
             // 路由检测(根据路由定义返回不同的URL调度)
             // 路由检测(根据路由定义返回不同的URL调度)
             $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
             $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
             $must   = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
             $must   = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
+
             if ($must && false === $result) {
             if ($must && false === $result) {
                 // 路由无效
                 // 路由无效
                 throw new RouteNotFoundException();
                 throw new RouteNotFoundException();
             }
             }
         }
         }
+
+        // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
         if (false === $result) {
         if (false === $result) {
-            // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
             $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
             $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
         }
         }
+
         return $result;
         return $result;
     }
     }
 
 

+ 90 - 60
thinkphp/library/think/Build.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -14,36 +14,44 @@ namespace think;
 class Build
 class Build
 {
 {
     /**
     /**
-     * 根据传入的build资料创建目录和文件
-     * @access protected
-     * @param  array  $build build列表
+     * 根据传入的 build 资料创建目录和文件
+     * @access public
+     * @param  array  $build     build 列表
      * @param  string $namespace 应用类库命名空间
      * @param  string $namespace 应用类库命名空间
-     * @param  bool   $suffix 类库后缀
+     * @param  bool   $suffix    类库后缀
      * @return void
      * @return void
+     * @throws Exception
      */
      */
     public static function run(array $build = [], $namespace = 'app', $suffix = false)
     public static function run(array $build = [], $namespace = 'app', $suffix = false)
     {
     {
         // 锁定
         // 锁定
-        $lockfile = APP_PATH . 'build.lock';
-        if (is_writable($lockfile)) {
-            return;
-        } elseif (!touch($lockfile)) {
-            throw new Exception('应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~', 10006);
-        }
-        foreach ($build as $module => $list) {
-            if ('__dir__' == $module) {
-                // 创建目录列表
-                self::buildDir($list);
-            } elseif ('__file__' == $module) {
-                // 创建文件列表
-                self::buildFile($list);
-            } else {
-                // 创建模块
-                self::module($module, $list, $namespace, $suffix);
+        $lock = APP_PATH . 'build.lock';
+
+        // 如果锁定文件不可写(不存在)则进行处理,否则表示已经有程序在处理了
+        if (!is_writable($lock)) {
+            if (!touch($lock)) {
+                throw new Exception(
+                    '应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~',
+                    10006
+                );
             }
             }
+
+            foreach ($build as $module => $list) {
+                if ('__dir__' == $module) {
+                    // 创建目录列表
+                    self::buildDir($list);
+                } elseif ('__file__' == $module) {
+                    // 创建文件列表
+                    self::buildFile($list);
+                } else {
+                    // 创建模块
+                    self::module($module, $list, $namespace, $suffix);
+                }
+            }
+
+            // 解除锁定
+            unlink($lock);
         }
         }
-        // 解除锁定
-        unlink($lockfile);
     }
     }
 
 
     /**
     /**
@@ -55,10 +63,8 @@ class Build
     protected static function buildDir($list)
     protected static function buildDir($list)
     {
     {
         foreach ($list as $dir) {
         foreach ($list as $dir) {
-            if (!is_dir(APP_PATH . $dir)) {
-                // 创建目录
-                mkdir(APP_PATH . $dir, 0755, true);
-            }
+            // 目录不存在则创建目录
+            !is_dir(APP_PATH . $dir) && mkdir(APP_PATH . $dir, 0755, true);
         }
         }
     }
     }
 
 
@@ -71,12 +77,17 @@ class Build
     protected static function buildFile($list)
     protected static function buildFile($list)
     {
     {
         foreach ($list as $file) {
         foreach ($list as $file) {
+            // 先创建目录
             if (!is_dir(APP_PATH . dirname($file))) {
             if (!is_dir(APP_PATH . dirname($file))) {
-                // 创建目录
                 mkdir(APP_PATH . dirname($file), 0755, true);
                 mkdir(APP_PATH . dirname($file), 0755, true);
             }
             }
+
+            // 再创建文件
             if (!is_file(APP_PATH . $file)) {
             if (!is_file(APP_PATH . $file)) {
-                file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : '');
+                file_put_contents(
+                    APP_PATH . $file,
+                    'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : ''
+                );
             }
             }
         }
         }
     }
     }
@@ -84,35 +95,37 @@ class Build
     /**
     /**
      * 创建模块
      * 创建模块
      * @access public
      * @access public
-     * @param  string $module 模块名
-     * @param  array  $list build列表
+     * @param  string $module    模块名
+     * @param  array  $list      build 列表
      * @param  string $namespace 应用类库命名空间
      * @param  string $namespace 应用类库命名空间
-     * @param  bool   $suffix 类库后缀
+     * @param  bool   $suffix    类库后缀
      * @return void
      * @return void
      */
      */
     public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)
     public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)
     {
     {
-        $module = $module ? $module : '';
-        if (!is_dir(APP_PATH . $module)) {
-            // 创建模块目录
-            mkdir(APP_PATH . $module);
-        }
+        $module = $module ?: '';
+
+        // 创建模块目录
+        !is_dir(APP_PATH . $module) && mkdir(APP_PATH . $module);
+
+        // 如果不是 runtime 目录则需要创建配置文件和公共文件、创建模块的默认页面
         if (basename(RUNTIME_PATH) != $module) {
         if (basename(RUNTIME_PATH) != $module) {
-            // 创建配置文件和公共文件
             self::buildCommon($module);
             self::buildCommon($module);
-            // 创建模块的默认页面
             self::buildHello($module, $namespace, $suffix);
             self::buildHello($module, $namespace, $suffix);
         }
         }
+
+        // 未指定文件和目录,则创建默认的模块目录和文件
         if (empty($list)) {
         if (empty($list)) {
-            // 创建默认的模块目录和文件
             $list = [
             $list = [
                 '__file__' => ['config.php', 'common.php'],
                 '__file__' => ['config.php', 'common.php'],
                 '__dir__'  => ['controller', 'model', 'view'],
                 '__dir__'  => ['controller', 'model', 'view'],
             ];
             ];
         }
         }
+
         // 创建子目录和文件
         // 创建子目录和文件
         foreach ($list as $path => $file) {
         foreach ($list as $path => $file) {
             $modulePath = APP_PATH . $module . DS;
             $modulePath = APP_PATH . $module . DS;
+
             if ('__dir__' == $path) {
             if ('__dir__' == $path) {
                 // 生成子目录
                 // 生成子目录
                 foreach ($file as $dir) {
                 foreach ($file as $dir) {
@@ -122,16 +135,20 @@ class Build
                 // 生成(空白)文件
                 // 生成(空白)文件
                 foreach ($file as $name) {
                 foreach ($file as $name) {
                     if (!is_file($modulePath . $name)) {
                     if (!is_file($modulePath . $name)) {
-                        file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : '');
+                        file_put_contents(
+                            $modulePath . $name,
+                            'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : ''
+                        );
                     }
                     }
                 }
                 }
             } else {
             } else {
-                // 生成相关MVC文件
+                // 生成相关 MVC 文件
                 foreach ($file as $val) {
                 foreach ($file as $val) {
                     $val      = trim($val);
                     $val      = trim($val);
                     $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;
                     $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;
                     $space    = $namespace . '\\' . ($module ? $module . '\\' : '') . $path;
                     $space    = $namespace . '\\' . ($module ? $module . '\\' : '') . $path;
                     $class    = $val . ($suffix ? ucfirst($path) : '');
                     $class    = $val . ($suffix ? ucfirst($path) : '');
+
                     switch ($path) {
                     switch ($path) {
                         case 'controller': // 控制器
                         case 'controller': // 控制器
                             $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
                             $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
@@ -159,18 +176,27 @@ class Build
 
 
     /**
     /**
      * 创建模块的欢迎页面
      * 创建模块的欢迎页面
-     * @access public
-     * @param  string $module 模块名
+     * @access protected
+     * @param  string $module    模块名
      * @param  string $namespace 应用类库命名空间
      * @param  string $namespace 应用类库命名空间
-     * @param  bool   $suffix 类库后缀
+     * @param  bool   $suffix    类库后缀
      * @return void
      * @return void
      */
      */
     protected static function buildHello($module, $namespace, $suffix = false)
     protected static function buildHello($module, $namespace, $suffix = false)
     {
     {
-        $filename = APP_PATH . ($module ? $module . DS : '') . 'controller' . DS . 'Index' . ($suffix ? 'Controller' : '') . EXT;
+        $filename = APP_PATH . ($module ? $module . DS : '') .
+            'controller' . DS . 'Index' .
+            ($suffix ? 'Controller' : '') . EXT;
+
         if (!is_file($filename)) {
         if (!is_file($filename)) {
-            $content = file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl');
-            $content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\' : '', 'controller', $suffix ? 'Controller' : ''], $content);
+            $module = $module ? $module . '\\' : '';
+            $suffix = $suffix ? 'Controller' : '';
+            $content = str_replace(
+                ['{$app}', '{$module}', '{layer}', '{$suffix}'],
+                [$namespace, $module, 'controller', $suffix],
+                file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl')
+            );
+
             self::checkDirBuild(dirname($filename));
             self::checkDirBuild(dirname($filename));
             file_put_contents($filename, $content);
             file_put_contents($filename, $content);
         }
         }
@@ -178,28 +204,32 @@ class Build
 
 
     /**
     /**
      * 创建模块的公共文件
      * 创建模块的公共文件
-     * @access public
+     * @access protected
      * @param  string $module 模块名
      * @param  string $module 模块名
      * @return void
      * @return void
      */
      */
     protected static function buildCommon($module)
     protected static function buildCommon($module)
     {
     {
-        $filename = CONF_PATH . ($module ? $module . DS : '') . 'config.php';
+        $config = CONF_PATH . ($module ? $module . DS : '') . 'config.php';
 
 
-        self::checkDirBuild(dirname($filename));
-        if (!is_file($filename)) {
-            file_put_contents($filename, "<?php\n//配置文件\nreturn [\n\n];");
-        }
-        $filename = APP_PATH . ($module ? $module . DS : '') . 'common.php';
-        if (!is_file($filename)) {
-            file_put_contents($filename, "<?php\n");
+        self::checkDirBuild(dirname($config));
+
+        if (!is_file($config)) {
+            file_put_contents($config, "<?php\n//配置文件\nreturn [\n\n];");
         }
         }
+
+        $common = APP_PATH . ($module ? $module . DS : '') . 'common.php';
+        if (!is_file($common)) file_put_contents($common, "<?php\n");
     }
     }
 
 
+    /**
+     * 创建目录
+     * @access protected
+     * @param  string $dirname 目录名称
+     * @return void
+     */
     protected static function checkDirBuild($dirname)
     protected static function checkDirBuild($dirname)
     {
     {
-        if (!is_dir($dirname)) {
-            mkdir($dirname, 0755, true);
-        }
+        !is_dir($dirname) && mkdir($dirname, 0755, true);
     }
     }
 }
 }

+ 68 - 43
thinkphp/library/think/Cache.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -15,71 +15,86 @@ use think\cache\Driver;
 
 
 class Cache
 class Cache
 {
 {
-    protected static $instance = [];
-    public static $readTimes   = 0;
-    public static $writeTimes  = 0;
+    /**
+     * @var array 缓存的实例
+     */
+    public static $instance = [];
+
+    /**
+     * @var int 缓存读取次数
+     */
+    public static $readTimes = 0;
+
+    /**
+     * @var int 缓存写入次数
+     */
+    public static $writeTimes = 0;
 
 
     /**
     /**
-     * 操作句柄
-     * @var object
-     * @access protected
+     * @var object 操作句柄
      */
      */
-    protected static $handler;
+    public static $handler;
 
 
     /**
     /**
-     * 连接缓存
+     * 连接缓存驱动
      * @access public
      * @access public
-     * @param array         $options  配置数组
-     * @param bool|string   $name 缓存连接标识 true 强制重新连接
+     * @param  array       $options 配置数组
+     * @param  bool|string $name    缓存连接标识 true 强制重新连接
      * @return Driver
      * @return Driver
      */
      */
     public static function connect(array $options = [], $name = false)
     public static function connect(array $options = [], $name = false)
     {
     {
         $type = !empty($options['type']) ? $options['type'] : 'File';
         $type = !empty($options['type']) ? $options['type'] : 'File';
+
         if (false === $name) {
         if (false === $name) {
             $name = md5(serialize($options));
             $name = md5(serialize($options));
         }
         }
 
 
         if (true === $name || !isset(self::$instance[$name])) {
         if (true === $name || !isset(self::$instance[$name])) {
-            $class = false !== strpos($type, '\\') ? $type : '\\think\\cache\\driver\\' . ucwords($type);
+            $class = false === strpos($type, '\\') ?
+            '\\think\\cache\\driver\\' . ucwords($type) :
+            $type;
 
 
             // 记录初始化信息
             // 记录初始化信息
             App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
             App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
+
             if (true === $name) {
             if (true === $name) {
                 return new $class($options);
                 return new $class($options);
-            } else {
-                self::$instance[$name] = new $class($options);
             }
             }
+
+            self::$instance[$name] = new $class($options);
         }
         }
+
         return self::$instance[$name];
         return self::$instance[$name];
     }
     }
 
 
     /**
     /**
      * 自动初始化缓存
      * 自动初始化缓存
      * @access public
      * @access public
-     * @param array         $options  配置数组
+     * @param  array $options 配置数组
      * @return Driver
      * @return Driver
      */
      */
     public static function init(array $options = [])
     public static function init(array $options = [])
     {
     {
         if (is_null(self::$handler)) {
         if (is_null(self::$handler)) {
-            // 自动初始化缓存
-            if (!empty($options)) {
-                $connect = self::connect($options);
-            } elseif ('complex' == Config::get('cache.type')) {
-                $connect = self::connect(Config::get('cache.default'));
-            } else {
-                $connect = self::connect(Config::get('cache'));
+            if (empty($options) && 'complex' == Config::get('cache.type')) {
+                $default = Config::get('cache.default');
+                // 获取默认缓存配置,并连接
+                $options = Config::get('cache.' . $default['type']) ?: $default;
+            } elseif (empty($options)) {
+                $options = Config::get('cache');
             }
             }
-            self::$handler = $connect;
+
+            self::$handler = self::connect($options);
         }
         }
+
         return self::$handler;
         return self::$handler;
     }
     }
 
 
     /**
     /**
      * 切换缓存类型 需要配置 cache.type 为 complex
      * 切换缓存类型 需要配置 cache.type 为 complex
      * @access public
      * @access public
-     * @param string $name 缓存标识
+     * @param  string $name 缓存标识
      * @return Driver
      * @return Driver
      */
      */
     public static function store($name = '')
     public static function store($name = '')
@@ -87,131 +102,141 @@ class Cache
         if ('' !== $name && 'complex' == Config::get('cache.type')) {
         if ('' !== $name && 'complex' == Config::get('cache.type')) {
             return self::connect(Config::get('cache.' . $name), strtolower($name));
             return self::connect(Config::get('cache.' . $name), strtolower($name));
         }
         }
+
         return self::init();
         return self::init();
     }
     }
 
 
     /**
     /**
      * 判断缓存是否存在
      * 判断缓存是否存在
      * @access public
      * @access public
-     * @param string $name 缓存变量名
+     * @param  string $name 缓存变量名
      * @return bool
      * @return bool
      */
      */
     public static function has($name)
     public static function has($name)
     {
     {
         self::$readTimes++;
         self::$readTimes++;
+
         return self::init()->has($name);
         return self::init()->has($name);
     }
     }
 
 
     /**
     /**
      * 读取缓存
      * 读取缓存
      * @access public
      * @access public
-     * @param string $name 缓存标识
-     * @param mixed  $default 默认值
+     * @param  string $name    缓存标识
+     * @param  mixed  $default 默认值
      * @return mixed
      * @return mixed
      */
      */
     public static function get($name, $default = false)
     public static function get($name, $default = false)
     {
     {
         self::$readTimes++;
         self::$readTimes++;
+
         return self::init()->get($name, $default);
         return self::init()->get($name, $default);
     }
     }
 
 
     /**
     /**
      * 写入缓存
      * 写入缓存
      * @access public
      * @access public
-     * @param string        $name 缓存标识
-     * @param mixed         $value  存储数据
-     * @param int|null      $expire  有效时间 0为永久
+     * @param  string   $name   缓存标识
+     * @param  mixed    $value  存储数据
+     * @param  int|null $expire 有效时间 0为永久
      * @return boolean
      * @return boolean
      */
      */
     public static function set($name, $value, $expire = null)
     public static function set($name, $value, $expire = null)
     {
     {
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->set($name, $value, $expire);
         return self::init()->set($name, $value, $expire);
     }
     }
 
 
     /**
     /**
      * 自增缓存(针对数值缓存)
      * 自增缓存(针对数值缓存)
      * @access public
      * @access public
-     * @param string    $name 缓存变量名
-     * @param int       $step 步长
+     * @param  string $name 缓存变量名
+     * @param  int    $step 步长
      * @return false|int
      * @return false|int
      */
      */
     public static function inc($name, $step = 1)
     public static function inc($name, $step = 1)
     {
     {
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->inc($name, $step);
         return self::init()->inc($name, $step);
     }
     }
 
 
     /**
     /**
      * 自减缓存(针对数值缓存)
      * 自减缓存(针对数值缓存)
      * @access public
      * @access public
-     * @param string    $name 缓存变量名
-     * @param int       $step 步长
+     * @param  string $name 缓存变量名
+     * @param  int    $step 步长
      * @return false|int
      * @return false|int
      */
      */
     public static function dec($name, $step = 1)
     public static function dec($name, $step = 1)
     {
     {
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->dec($name, $step);
         return self::init()->dec($name, $step);
     }
     }
 
 
     /**
     /**
      * 删除缓存
      * 删除缓存
      * @access public
      * @access public
-     * @param string    $name 缓存标识
+     * @param  string $name 缓存标识
      * @return boolean
      * @return boolean
      */
      */
     public static function rm($name)
     public static function rm($name)
     {
     {
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->rm($name);
         return self::init()->rm($name);
     }
     }
 
 
     /**
     /**
      * 清除缓存
      * 清除缓存
      * @access public
      * @access public
-     * @param string $tag 标签名
+     * @param  string $tag 标签名
      * @return boolean
      * @return boolean
      */
      */
     public static function clear($tag = null)
     public static function clear($tag = null)
     {
     {
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->clear($tag);
         return self::init()->clear($tag);
     }
     }
 
 
     /**
     /**
      * 读取缓存并删除
      * 读取缓存并删除
      * @access public
      * @access public
-     * @param string $name 缓存变量名
+     * @param  string $name 缓存变量名
      * @return mixed
      * @return mixed
      */
      */
     public static function pull($name)
     public static function pull($name)
     {
     {
         self::$readTimes++;
         self::$readTimes++;
         self::$writeTimes++;
         self::$writeTimes++;
+
         return self::init()->pull($name);
         return self::init()->pull($name);
     }
     }
 
 
     /**
     /**
      * 如果不存在则写入缓存
      * 如果不存在则写入缓存
      * @access public
      * @access public
-     * @param string    $name 缓存变量名
-     * @param mixed     $value  存储数据
-     * @param int       $expire  有效时间 0为永久
+     * @param  string $name   缓存变量名
+     * @param  mixed  $value  存储数据
+     * @param  int    $expire 有效时间 0为永久
      * @return mixed
      * @return mixed
      */
      */
     public static function remember($name, $value, $expire = null)
     public static function remember($name, $value, $expire = null)
     {
     {
         self::$readTimes++;
         self::$readTimes++;
+
         return self::init()->remember($name, $value, $expire);
         return self::init()->remember($name, $value, $expire);
     }
     }
 
 
     /**
     /**
      * 缓存标签
      * 缓存标签
      * @access public
      * @access public
-     * @param string        $name 标签名
-     * @param string|array  $keys 缓存标识
-     * @param bool          $overlay 是否覆盖
+     * @param  string       $name    标签名
+     * @param  string|array $keys    缓存标识
+     * @param  bool         $overlay 是否覆盖
      * @return Driver
      * @return Driver
      */
      */
     public static function tag($name, $keys = null, $overlay = false)
     public static function tag($name, $keys = null, $overlay = false)

+ 209 - 118
thinkphp/library/think/Collection.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -19,20 +19,35 @@ use JsonSerializable;
 
 
 class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
 class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
 {
 {
+    /**
+     * @var array 数据
+     */
     protected $items = [];
     protected $items = [];
 
 
+    /**
+     * Collection constructor.
+     * @access public
+     * @param  array $items 数据
+     */
     public function __construct($items = [])
     public function __construct($items = [])
     {
     {
         $this->items = $this->convertToArray($items);
         $this->items = $this->convertToArray($items);
     }
     }
 
 
+    /**
+     * 创建 Collection 实例
+     * @access public
+     * @param  array $items 数据
+     * @return static
+     */
     public static function make($items = [])
     public static function make($items = [])
     {
     {
         return new static($items);
         return new static($items);
     }
     }
 
 
     /**
     /**
-     * 是否为空
+     * 判断数据是否为空
+     * @access public
      * @return bool
      * @return bool
      */
      */
     public function isEmpty()
     public function isEmpty()
@@ -40,74 +55,96 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
         return empty($this->items);
         return empty($this->items);
     }
     }
 
 
+    /**
+     * 将数据转成数组
+     * @access public
+     * @return array
+     */
     public function toArray()
     public function toArray()
     {
     {
         return array_map(function ($value) {
         return array_map(function ($value) {
-            return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
+            return ($value instanceof Model || $value instanceof self) ?
+                $value->toArray() :
+                $value;
         }, $this->items);
         }, $this->items);
     }
     }
 
 
+    /**
+     * 获取全部的数据
+     * @access public
+     * @return array
+     */
     public function all()
     public function all()
     {
     {
         return $this->items;
         return $this->items;
     }
     }
 
 
     /**
     /**
-     * 合并数组
-     *
-     * @param  mixed $items
+     * 交换数组中的键和值
+     * @access public
      * @return static
      * @return static
      */
      */
-    public function merge($items)
+    public function flip()
     {
     {
-        return new static(array_merge($this->items, $this->convertToArray($items)));
+        return new static(array_flip($this->items));
     }
     }
 
 
     /**
     /**
-     * 比较数组,返回差集
-     *
-     * @param  mixed $items
+     * 返回数组中所有的键名组成的新 Collection 实例
+     * @access public
      * @return static
      * @return static
      */
      */
-    public function diff($items)
+    public function keys()
     {
     {
-        return new static(array_diff($this->items, $this->convertToArray($items)));
+        return new static(array_keys($this->items));
     }
     }
 
 
     /**
     /**
-     * 交换数组中的键和值
-     *
+     * 返回数组中所有的值组成的新 Collection 实例
+     * @access public
      * @return static
      * @return static
      */
      */
-    public function flip()
+    public function values()
     {
     {
-        return new static(array_flip($this->items));
+        return new static(array_values($this->items));
     }
     }
 
 
     /**
     /**
-     * 比较数组,返回交集
-     *
-     * @param  mixed $items
+     * 合并数组并返回一个新的 Collection 实例
+     * @access public
+     * @param  mixed $items 新的数据
      * @return static
      * @return static
      */
      */
-    public function intersect($items)
+    public function merge($items)
     {
     {
-        return new static(array_intersect($this->items, $this->convertToArray($items)));
+        return new static(array_merge($this->items, $this->convertToArray($items)));
     }
     }
 
 
     /**
     /**
-     * 返回数组中所有的键名
-     *
+     * 比较数组,返回差集生成的新 Collection 实例
+     * @access public
+     * @param  mixed $items 做比较的数据
      * @return static
      * @return static
      */
      */
-    public function keys()
+    public function diff($items)
     {
     {
-        return new static(array_keys($this->items));
+        return new static(array_diff($this->items, $this->convertToArray($items)));
+    }
+
+    /**
+     * 比较数组,返回交集组成的 Collection 新实例
+     * @access public
+     * @param  mixed $items 比较数据
+     * @return static
+     */
+    public function intersect($items)
+    {
+        return new static(array_intersect($this->items, $this->convertToArray($items)));
     }
     }
 
 
     /**
     /**
-     * 删除数组的最后一个元素(出栈)
-     *
+     * 返回并删除数据中的的最后一个元素(出栈)
+     * @access public
      * @return mixed
      * @return mixed
      */
      */
     public function pop()
     public function pop()
@@ -116,42 +153,74 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
     }
     }
 
 
     /**
     /**
-     * 通过使用用户自定义函数,以字符串返回数组
-     *
-     * @param  callable $callback
-     * @param  mixed    $initial
+     * 返回并删除数据中首个元素
+     * @access public
      * @return mixed
      * @return mixed
      */
      */
-    public function reduce(callable $callback, $initial = null)
+    public function shift()
     {
     {
-        return array_reduce($this->items, $callback, $initial);
+        return array_shift($this->items);
     }
     }
 
 
     /**
     /**
-     * 以相反的顺序返回数组。
-     *
-     * @return static
+     * 在数组开头插入一个元素
+     * @access public
+     * @param mixed $value 值
+     * @param mixed $key   键名
+     * @return void
      */
      */
-    public function reverse()
+    public function unshift($value, $key = null)
     {
     {
-        return new static(array_reverse($this->items));
+        if (is_null($key)) {
+            array_unshift($this->items, $value);
+        } else {
+            $this->items = [$key => $value] + $this->items;
+        }
+    }
+
+    /**
+     * 在数组结尾插入一个元素
+     * @access public
+     * @param  mixed $value 值
+     * @param  mixed $key   键名
+     * @return void
+     */
+    public function push($value, $key = null)
+    {
+        if (is_null($key)) {
+            $this->items[] = $value;
+        } else {
+            $this->items[$key] = $value;
+        }
     }
     }
 
 
     /**
     /**
-     * 删除数组中首个元素,并返回被删除元素的值
-     *
+     * 通过使用用户自定义函数,以字符串返回数组
+     * @access public
+     * @param  callable $callback 回调函数
+     * @param  mixed    $initial  初始值
      * @return mixed
      * @return mixed
      */
      */
-    public function shift()
+    public function reduce(callable $callback, $initial = null)
     {
     {
-        return array_shift($this->items);
+        return array_reduce($this->items, $callback, $initial);
+    }
+
+    /**
+     * 以相反的顺序创建一个新的 Collection 实例
+     * @access public
+     * @return static
+     */
+    public function reverse()
+    {
+        return new static(array_reverse($this->items));
     }
     }
 
 
     /**
     /**
-     * 把一个数组分割为新的数组块.
-     *
-     * @param  int  $size
-     * @param  bool $preserveKeys
+     * 把数据分割为新的数组块
+     * @access public
+     * @param  int  $size         分隔长度
+     * @param  bool $preserveKeys 是否保持原数据索引
      * @return static
      * @return static
      */
      */
     public function chunk($size, $preserveKeys = false)
     public function chunk($size, $preserveKeys = false)
@@ -166,33 +235,21 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
     }
     }
 
 
     /**
     /**
-     * 在数组开头插入一个元素
-     * @param mixed $value
-     * @param null  $key
-     * @return int
-     */
-    public function unshift($value, $key = null)
-    {
-        if (is_null($key)) {
-            array_unshift($this->items, $value);
-        } else {
-            $this->items = [$key => $value] + $this->items;
-        }
-    }
-
-    /**
-     * 给每个元素执行个回调
-     *
-     * @param  callable $callback
+     * 给数据中的每个元素执行回调
+     * @access public
+     * @param  callable $callback 回调函数
      * @return $this
      * @return $this
      */
      */
     public function each(callable $callback)
     public function each(callable $callback)
     {
     {
         foreach ($this->items as $key => $item) {
         foreach ($this->items as $key => $item) {
             $result = $callback($item, $key);
             $result = $callback($item, $key);
+
             if (false === $result) {
             if (false === $result) {
                 break;
                 break;
-            } elseif (!is_object($item)) {
+            }
+
+            if (!is_object($item)) {
                 $this->items[$key] = $result;
                 $this->items[$key] = $result;
             }
             }
         }
         }
@@ -201,46 +258,47 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
     }
     }
 
 
     /**
     /**
-     * 用回调函数过滤数组中的元素
-     * @param callable|null $callback
+     * 用回调函数过滤数据中的元素
+     * @access public
+     * @param callable|null $callback 回调函数
      * @return static
      * @return static
      */
      */
     public function filter(callable $callback = null)
     public function filter(callable $callback = null)
     {
     {
-        if ($callback) {
-            return new static(array_filter($this->items, $callback));
-        }
-
-        return new static(array_filter($this->items));
+        return new static(array_filter($this->items, $callback ?: null));
     }
     }
 
 
     /**
     /**
-     * 返回数组中指定的一列
-     * @param      $column_key
-     * @param null $index_key
+     * 返回数据中指定的一列
+     * @access public
+     * @param mixed $columnKey 键名
+     * @param null  $indexKey  作为索引值的列
      * @return array
      * @return array
      */
      */
-    public function column($column_key, $index_key = null)
+    public function column($columnKey, $indexKey = null)
     {
     {
         if (function_exists('array_column')) {
         if (function_exists('array_column')) {
-            return array_column($this->items, $column_key, $index_key);
+            return array_column($this->items, $columnKey, $indexKey);
         }
         }
 
 
         $result = [];
         $result = [];
         foreach ($this->items as $row) {
         foreach ($this->items as $row) {
-            $key    = $value    = null;
+            $key    = $value = null;
             $keySet = $valueSet = false;
             $keySet = $valueSet = false;
-            if (null !== $index_key && array_key_exists($index_key, $row)) {
+
+            if (null !== $indexKey && array_key_exists($indexKey, $row)) {
+                $key    = (string) $row[$indexKey];
                 $keySet = true;
                 $keySet = true;
-                $key    = (string) $row[$index_key];
             }
             }
-            if (null === $column_key) {
+
+            if (null === $columnKey) {
                 $valueSet = true;
                 $valueSet = true;
                 $value    = $row;
                 $value    = $row;
-            } elseif (is_array($row) && array_key_exists($column_key, $row)) {
+            } elseif (is_array($row) && array_key_exists($columnKey, $row)) {
                 $valueSet = true;
                 $valueSet = true;
-                $value    = $row[$column_key];
+                $value    = $row[$columnKey];
             }
             }
+
             if ($valueSet) {
             if ($valueSet) {
                 if ($keySet) {
                 if ($keySet) {
                     $result[$key] = $value;
                     $result[$key] = $value;
@@ -249,34 +307,30 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
                 }
                 }
             }
             }
         }
         }
+
         return $result;
         return $result;
     }
     }
 
 
     /**
     /**
-     * 对数组排序
-     *
-     * @param  callable|null $callback
+     * 对数据排序,并返回排序后的数据组成的新 Collection 实例
+     * @access public
+     * @param  callable|null $callback 回调函数
      * @return static
      * @return static
      */
      */
     public function sort(callable $callback = null)
     public function sort(callable $callback = null)
     {
     {
-        $items = $this->items;
-
-        $callback ? uasort($items, $callback) : uasort($items, function ($a, $b) {
-
-            if ($a == $b) {
-                return 0;
-            }
-
-            return ($a < $b) ? -1 : 1;
-        });
+        $items    = $this->items;
+        $callback = $callback ?: function ($a, $b) {
+            return $a == $b ? 0 : (($a < $b) ? -1 : 1);
+        };
 
 
+        uasort($items, $callback);
         return new static($items);
         return new static($items);
     }
     }
 
 
     /**
     /**
-     * 将数组打乱
-     *
+     * 将数据打乱后组成新的 Collection 实例
+     * @access public
      * @return static
      * @return static
      */
      */
     public function shuffle()
     public function shuffle()
@@ -284,16 +338,15 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
         $items = $this->items;
         $items = $this->items;
 
 
         shuffle($items);
         shuffle($items);
-
         return new static($items);
         return new static($items);
     }
     }
 
 
     /**
     /**
-     * 截取数
-     *
-     * @param  int  $offset
-     * @param  int  $length
-     * @param  bool $preserveKeys
+     * 截取数据并返回新的 Collection 实例
+     * @access public
+     * @param  int  $offset       起始位置
+     * @param  int  $length       截取长度
+     * @param  bool $preserveKeys 是否保持原先的键名
      * @return static
      * @return static
      */
      */
     public function slice($offset, $length = null, $preserveKeys = false)
     public function slice($offset, $length = null, $preserveKeys = false)
@@ -301,17 +354,35 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
         return new static(array_slice($this->items, $offset, $length, $preserveKeys));
         return new static(array_slice($this->items, $offset, $length, $preserveKeys));
     }
     }
 
 
-    // ArrayAccess
+    /**
+     * 指定的键是否存在
+     * @access public
+     * @param  mixed $offset 键名
+     * @return bool
+     */
     public function offsetExists($offset)
     public function offsetExists($offset)
     {
     {
         return array_key_exists($offset, $this->items);
         return array_key_exists($offset, $this->items);
     }
     }
 
 
+    /**
+     * 获取指定键对应的值
+     * @access public
+     * @param  mixed $offset 键名
+     * @return mixed
+     */
     public function offsetGet($offset)
     public function offsetGet($offset)
     {
     {
         return $this->items[$offset];
         return $this->items[$offset];
     }
     }
 
 
+    /**
+     * 设置键值
+     * @access public
+     * @param  mixed $offset 键名
+     * @param  mixed $value  值
+     * @return void
+     */
     public function offsetSet($offset, $value)
     public function offsetSet($offset, $value)
     {
     {
         if (is_null($offset)) {
         if (is_null($offset)) {
@@ -321,33 +392,51 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
         }
         }
     }
     }
 
 
+    /**
+     * 删除指定键值
+     * @access public
+     * @param  mixed $offset 键名
+     * @return void
+     */
     public function offsetUnset($offset)
     public function offsetUnset($offset)
     {
     {
         unset($this->items[$offset]);
         unset($this->items[$offset]);
     }
     }
 
 
-    //Countable
+    /**
+     * 统计数据的个数
+     * @access public
+     * @return int
+     */
     public function count()
     public function count()
     {
     {
         return count($this->items);
         return count($this->items);
     }
     }
 
 
-    //IteratorAggregate
+    /**
+     * 获取数据的迭代器
+     * @access public
+     * @return ArrayIterator
+     */
     public function getIterator()
     public function getIterator()
     {
     {
         return new ArrayIterator($this->items);
         return new ArrayIterator($this->items);
     }
     }
 
 
-    //JsonSerializable
+    /**
+     * 将数据反序列化成数组
+     * @access public
+     * @return array
+     */
     public function jsonSerialize()
     public function jsonSerialize()
     {
     {
         return $this->toArray();
         return $this->toArray();
     }
     }
 
 
     /**
     /**
-     * 转换当前数据集为JSON字符串
+     * 转换当前数据集为 JSON 字符串
      * @access public
      * @access public
-     * @param integer $options json参数
+     * @param  integer $options json 参数
      * @return string
      * @return string
      */
      */
     public function toJson($options = JSON_UNESCAPED_UNICODE)
     public function toJson($options = JSON_UNESCAPED_UNICODE)
@@ -355,22 +444,24 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
         return json_encode($this->toArray(), $options);
         return json_encode($this->toArray(), $options);
     }
     }
 
 
+    /**
+     * 将数据转换成字符串
+     * @access public
+     * @return string
+     */
     public function __toString()
     public function __toString()
     {
     {
         return $this->toJson();
         return $this->toJson();
     }
     }
 
 
     /**
     /**
-     * 转换成数组
-     *
-     * @param  mixed $items
+     * 将数据转换成数组
+     * @access protected
+     * @param  mixed $items 数据
      * @return array
      * @return array
      */
      */
     protected function convertToArray($items)
     protected function convertToArray($items)
     {
     {
-        if ($items instanceof self) {
-            return $items->all();
-        }
-        return (array) $items;
+        return $items instanceof self ? $items->all() : (array) $items;
     }
     }
 }
 }

+ 99 - 63
thinkphp/library/think/Config.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -13,70 +13,88 @@ namespace think;
 
 
 class Config
 class Config
 {
 {
-    // 配置参数
+    /**
+     * @var array 配置参数
+     */
     private static $config = [];
     private static $config = [];
-    // 参数作用域
+
+    /**
+     * @var string 参数作用域
+     */
     private static $range = '_sys_';
     private static $range = '_sys_';
 
 
-    // 设定配置参数的作用域
+    /**
+     * 设定配置参数的作用域
+     * @access public
+     * @param  string $range 作用域
+     * @return void
+     */
     public static function range($range)
     public static function range($range)
     {
     {
         self::$range = $range;
         self::$range = $range;
-        if (!isset(self::$config[$range])) {
-            self::$config[$range] = [];
-        }
+
+        if (!isset(self::$config[$range])) self::$config[$range] = [];
     }
     }
 
 
     /**
     /**
      * 解析配置文件或内容
      * 解析配置文件或内容
-     * @param string    $config 配置文件路径或内容
-     * @param string    $type 配置解析类型
-     * @param string    $name 配置名(如设置即表示二级配置)
-     * @param string    $range  作用域
+     * @access public
+     * @param  string $config 配置文件路径或内容
+     * @param  string $type   配置解析类型
+     * @param  string $name   配置名(如设置即表示二级配置)
+     * @param  string $range  作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function parse($config, $type = '', $name = '', $range = '')
     public static function parse($config, $type = '', $name = '', $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
-        if (empty($type)) {
-            $type = pathinfo($config, PATHINFO_EXTENSION);
-        }
-        $class = false !== strpos($type, '\\') ? $type : '\\think\\config\\driver\\' . ucwords($type);
+
+        if (empty($type)) $type = pathinfo($config, PATHINFO_EXTENSION);
+
+        $class = false !== strpos($type, '\\') ?
+            $type :
+            '\\think\\config\\driver\\' . ucwords($type);
+
         return self::set((new $class())->parse($config), $name, $range);
         return self::set((new $class())->parse($config), $name, $range);
     }
     }
 
 
     /**
     /**
      * 加载配置文件(PHP格式)
      * 加载配置文件(PHP格式)
-     * @param string    $file 配置文件名
-     * @param string    $name 配置名(如设置即表示二级配置)
-     * @param string    $range  作用域
+     * @access public
+     * @param  string $file  配置文件名
+     * @param  string $name  配置名(如设置即表示二级配置)
+     * @param  string $range 作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function load($file, $name = '', $range = '')
     public static function load($file, $name = '', $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
-        if (!isset(self::$config[$range])) {
-            self::$config[$range] = [];
-        }
+
+        if (!isset(self::$config[$range])) self::$config[$range] = [];
+
         if (is_file($file)) {
         if (is_file($file)) {
             $name = strtolower($name);
             $name = strtolower($name);
             $type = pathinfo($file, PATHINFO_EXTENSION);
             $type = pathinfo($file, PATHINFO_EXTENSION);
+
             if ('php' == $type) {
             if ('php' == $type) {
                 return self::set(include $file, $name, $range);
                 return self::set(include $file, $name, $range);
-            } elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
+            }
+
+            if ('yaml' == $type && function_exists('yaml_parse_file')) {
                 return self::set(yaml_parse_file($file), $name, $range);
                 return self::set(yaml_parse_file($file), $name, $range);
-            } else {
-                return self::parse($file, $type, $name, $range);
             }
             }
-        } else {
-            return self::$config[$range];
+
+            return self::parse($file, $type, $name, $range);
         }
         }
+
+        return self::$config[$range];
     }
     }
 
 
     /**
     /**
      * 检测配置是否存在
      * 检测配置是否存在
-     * @param string    $name 配置参数名(支持二级配置 .号分割)
-     * @param string    $range  作用域
+     * @access public
+     * @param  string $name 配置参数名(支持二级配置 . 号分割)
+     * @param  string $range  作用域
      * @return bool
      * @return bool
      */
      */
     public static function has($name, $range = '')
     public static function has($name, $range = '')
@@ -85,90 +103,108 @@ class Config
 
 
         if (!strpos($name, '.')) {
         if (!strpos($name, '.')) {
             return isset(self::$config[$range][strtolower($name)]);
             return isset(self::$config[$range][strtolower($name)]);
-        } else {
-            // 二维数组设置和获取支持
-            $name = explode('.', $name, 2);
-            return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
         }
         }
+
+        // 二维数组设置和获取支持
+        $name = explode('.', $name, 2);
+        return isset(self::$config[$range][strtolower($name[0])][$name[1]]);
     }
     }
 
 
     /**
     /**
      * 获取配置参数 为空则获取所有配置
      * 获取配置参数 为空则获取所有配置
-     * @param string    $name 配置参数名(支持二级配置 .号分割)
-     * @param string    $range  作用域
+     * @access public
+     * @param  string $name 配置参数名(支持二级配置 . 号分割)
+     * @param  string $range  作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function get($name = null, $range = '')
     public static function get($name = null, $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
+
         // 无参数时获取所有
         // 无参数时获取所有
         if (empty($name) && isset(self::$config[$range])) {
         if (empty($name) && isset(self::$config[$range])) {
             return self::$config[$range];
             return self::$config[$range];
         }
         }
 
 
+        // 非二级配置时直接返回
         if (!strpos($name, '.')) {
         if (!strpos($name, '.')) {
             $name = strtolower($name);
             $name = strtolower($name);
             return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;
             return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;
-        } else {
-            // 二维数组设置和获取支持
-            $name    = explode('.', $name, 2);
-            $name[0] = strtolower($name[0]);
+        }
 
 
-            if (!isset(self::$config[$range][$name[0]])) {
-                // 动态载入额外配置
-                $module = Request::instance()->module();
-                $file   = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT;
+        // 二维数组设置和获取支持
+        $name    = explode('.', $name, 2);
+        $name[0] = strtolower($name[0]);
 
 
-                is_file($file) && self::load($file, $name[0]);
-            }
+        if (!isset(self::$config[$range][$name[0]])) {
+            // 动态载入额外配置
+            $module = Request::instance()->module();
+            $file   = CONF_PATH . ($module ? $module . DS : '') . 'extra' . DS . $name[0] . CONF_EXT;
 
 
-            return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null;
+            is_file($file) && self::load($file, $name[0]);
         }
         }
+
+        return isset(self::$config[$range][$name[0]][$name[1]]) ?
+            self::$config[$range][$name[0]][$name[1]] :
+            null;
     }
     }
 
 
     /**
     /**
-     * 设置配置参数 name为数组则为批量设置
-     * @param string|array  $name 配置参数名(支持二级配置 .号分割)
-     * @param mixed         $value 配置值
-     * @param string        $range  作用域
+     * 设置配置参数 name 为数组则为批量设置
+     * @access public
+     * @param  string|array $name  配置参数名(支持二级配置 . 号分割)
+     * @param  mixed        $value 配置值
+     * @param  string       $range 作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function set($name, $value = null, $range = '')
     public static function set($name, $value = null, $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
-        if (!isset(self::$config[$range])) {
-            self::$config[$range] = [];
-        }
+
+        if (!isset(self::$config[$range])) self::$config[$range] = [];
+
+        // 字符串则表示单个配置设置
         if (is_string($name)) {
         if (is_string($name)) {
             if (!strpos($name, '.')) {
             if (!strpos($name, '.')) {
                 self::$config[$range][strtolower($name)] = $value;
                 self::$config[$range][strtolower($name)] = $value;
             } else {
             } else {
-                // 二维数组设置和获取支持
-                $name                                                 = explode('.', $name, 2);
+                // 二维数组
+                $name = explode('.', $name, 2);
                 self::$config[$range][strtolower($name[0])][$name[1]] = $value;
                 self::$config[$range][strtolower($name[0])][$name[1]] = $value;
             }
             }
-            return;
-        } elseif (is_array($name)) {
-            // 批量设置
+
+            return $value;
+        }
+
+        // 数组则表示批量设置
+        if (is_array($name)) {
             if (!empty($value)) {
             if (!empty($value)) {
                 self::$config[$range][$value] = isset(self::$config[$range][$value]) ?
                 self::$config[$range][$value] = isset(self::$config[$range][$value]) ?
-                array_merge(self::$config[$range][$value], $name) : $name;
+                    array_merge(self::$config[$range][$value], $name) :
+                    $name;
+
                 return self::$config[$range][$value];
                 return self::$config[$range][$value];
-            } else {
-                return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name));
             }
             }
-        } else {
-            // 为空直接返回 已有配置
-            return self::$config[$range];
+
+            return self::$config[$range] = array_merge(
+                self::$config[$range], array_change_key_case($name)
+            );
         }
         }
+
+        // 为空直接返回已有配置
+        return self::$config[$range];
     }
     }
 
 
     /**
     /**
      * 重置配置参数
      * 重置配置参数
+     * @access public
+     * @param  string $range 作用域
+     * @return void
      */
      */
     public static function reset($range = '')
     public static function reset($range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
+
         if (true === $range) {
         if (true === $range) {
             self::$config = [];
             self::$config = [];
         } else {
         } else {

+ 266 - 122
thinkphp/library/think/Console.php

@@ -20,20 +20,49 @@ use think\console\output\driver\Buffer;
 
 
 class Console
 class Console
 {
 {
-
+    /**
+     * @var string 命令名称
+     */
     private $name;
     private $name;
+
+    /**
+     * @var string 命令版本
+     */
     private $version;
     private $version;
 
 
-    /** @var Command[] */
+    /**
+     * @var Command[] 命令
+     */
     private $commands = [];
     private $commands = [];
 
 
+    /**
+     * @var bool 是否需要帮助信息
+     */
     private $wantHelps = false;
     private $wantHelps = false;
 
 
+    /**
+     * @var bool 是否捕获异常
+     */
     private $catchExceptions = true;
     private $catchExceptions = true;
-    private $autoExit        = true;
+
+    /**
+     * @var bool 是否自动退出执行
+     */
+    private $autoExit = true;
+
+    /**
+     * @var InputDefinition 输入定义
+     */
     private $definition;
     private $definition;
+
+    /**
+     * @var string 默认执行的命令
+     */
     private $defaultCommand;
     private $defaultCommand;
 
 
+    /**
+     * @var array 默认提供的命令
+     */
     private static $defaultCommands = [
     private static $defaultCommands = [
         "think\\console\\command\\Help",
         "think\\console\\command\\Help",
         "think\\console\\command\\Lists",
         "think\\console\\command\\Lists",
@@ -47,11 +76,22 @@ class Console
         "think\\console\\command\\optimize\\Schema",
         "think\\console\\command\\optimize\\Schema",
     ];
     ];
 
 
-    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
+    /**
+     * Console constructor.
+     * @access public
+     * @param  string     $name    名称
+     * @param  string     $version 版本
+     * @param null|string $user    执行用户
+     */
+    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null)
     {
     {
         $this->name    = $name;
         $this->name    = $name;
         $this->version = $version;
         $this->version = $version;
 
 
+        if ($user) {
+            $this->setUser($user);
+        }
+
         $this->defaultCommand = 'list';
         $this->defaultCommand = 'list';
         $this->definition     = $this->getDefaultInputDefinition();
         $this->definition     = $this->getDefaultInputDefinition();
 
 
@@ -60,38 +100,58 @@ class Console
         }
         }
     }
     }
 
 
+    /**
+     * 设置执行用户
+     * @param $user
+     */
+    public function setUser($user)
+    {
+        $user = posix_getpwnam($user);
+        if ($user) {
+            posix_setuid($user['uid']);
+            posix_setgid($user['gid']);
+        }
+    }
+
+    /**
+     * 初始化 Console
+     * @access public
+     * @param  bool $run 是否运行 Console
+     * @return int|Console
+     */
     public static function init($run = true)
     public static function init($run = true)
     {
     {
         static $console;
         static $console;
+
         if (!$console) {
         if (!$console) {
-            // 实例化console
-            $console = new self('Think Console', '0.1');
+            $config = Config::get('console');
+            // 实例化 console
+            $console = new self($config['name'], $config['version'], $config['user']);
+
             // 读取指令集
             // 读取指令集
             if (is_file(CONF_PATH . 'command' . EXT)) {
             if (is_file(CONF_PATH . 'command' . EXT)) {
                 $commands = include CONF_PATH . 'command' . EXT;
                 $commands = include CONF_PATH . 'command' . EXT;
+
                 if (is_array($commands)) {
                 if (is_array($commands)) {
                     foreach ($commands as $command) {
                     foreach ($commands as $command) {
-                        if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) {
-                            // 注册指令
-                            $console->add(new $command());
-                        }
+                        class_exists($command) &&
+                        is_subclass_of($command, "\\think\\console\\Command") &&
+                        $console->add(new $command());  // 注册指令
                     }
                     }
                 }
                 }
             }
             }
         }
         }
-        if ($run) {
-            // 运行
-            return $console->run();
-        } else {
-            return $console;
-        }
+
+        return $run ? $console->run() : $console;
     }
     }
 
 
     /**
     /**
-     * @param        $command
-     * @param array  $parameters
-     * @param string $driver
-     * @return Output|Buffer
+     * 调用命令
+     * @access public
+     * @param  string $command
+     * @param  array  $parameters
+     * @param  string $driver
+     * @return Output
      */
      */
     public static function call($command, array $parameters = [], $driver = 'buffer')
     public static function call($command, array $parameters = [], $driver = 'buffer')
     {
     {
@@ -110,9 +170,9 @@ class Console
 
 
     /**
     /**
      * 执行当前的指令
      * 执行当前的指令
+     * @access public
      * @return int
      * @return int
      * @throws \Exception
      * @throws \Exception
-     * @api
      */
      */
     public function run()
     public function run()
     {
     {
@@ -124,27 +184,21 @@ class Console
         try {
         try {
             $exitCode = $this->doRun($input, $output);
             $exitCode = $this->doRun($input, $output);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
-            if (!$this->catchExceptions) {
-                throw $e;
-            }
+            if (!$this->catchExceptions) throw $e;
 
 
             $output->renderException($e);
             $output->renderException($e);
 
 
             $exitCode = $e->getCode();
             $exitCode = $e->getCode();
+
             if (is_numeric($exitCode)) {
             if (is_numeric($exitCode)) {
-                $exitCode = (int) $exitCode;
-                if (0 === $exitCode) {
-                    $exitCode = 1;
-                }
+                $exitCode = ((int) $exitCode) ?: 1;
             } else {
             } else {
                 $exitCode = 1;
                 $exitCode = 1;
             }
             }
         }
         }
 
 
         if ($this->autoExit) {
         if ($this->autoExit) {
-            if ($exitCode > 255) {
-                $exitCode = 255;
-            }
+            if ($exitCode > 255) $exitCode = 255;
 
 
             exit($exitCode);
             exit($exitCode);
         }
         }
@@ -154,12 +208,14 @@ class Console
 
 
     /**
     /**
      * 执行指令
      * 执行指令
-     * @param Input  $input
-     * @param Output $output
+     * @access public
+     * @param  Input  $input  输入
+     * @param  Output $output 输出
      * @return int
      * @return int
      */
      */
     public function doRun(Input $input, Output $output)
     public function doRun(Input $input, Output $output)
     {
     {
+        // 获取版本信息
         if (true === $input->hasParameterOption(['--version', '-V'])) {
         if (true === $input->hasParameterOption(['--version', '-V'])) {
             $output->writeln($this->getLongVersion());
             $output->writeln($this->getLongVersion());
 
 
@@ -168,6 +224,7 @@ class Console
 
 
         $name = $this->getCommandName($input);
         $name = $this->getCommandName($input);
 
 
+        // 获取帮助信息
         if (true === $input->hasParameterOption(['--help', '-h'])) {
         if (true === $input->hasParameterOption(['--help', '-h'])) {
             if (!$name) {
             if (!$name) {
                 $name  = 'help';
                 $name  = 'help';
@@ -182,25 +239,26 @@ class Console
             $input = new Input([$this->defaultCommand]);
             $input = new Input([$this->defaultCommand]);
         }
         }
 
 
-        $command = $this->find($name);
-
-        $exitCode = $this->doRunCommand($command, $input, $output);
-
-        return $exitCode;
+        return $this->doRunCommand($this->find($name), $input, $output);
     }
     }
 
 
     /**
     /**
      * 设置输入参数定义
      * 设置输入参数定义
-     * @param InputDefinition $definition
+     * @access public
+     * @param  InputDefinition $definition 输入定义
+     * @return $this;
      */
      */
     public function setDefinition(InputDefinition $definition)
     public function setDefinition(InputDefinition $definition)
     {
     {
         $this->definition = $definition;
         $this->definition = $definition;
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 获取输入参数定义
      * 获取输入参数定义
-     * @return InputDefinition The InputDefinition instance
+     * @access public
+     * @return InputDefinition
      */
      */
     public function getDefinition()
     public function getDefinition()
     {
     {
@@ -208,8 +266,9 @@ class Console
     }
     }
 
 
     /**
     /**
-     * Gets the help message.
-     * @return string A help message.
+     * 获取帮助信息
+     * @access public
+     * @return string
      */
      */
     public function getHelp()
     public function getHelp()
     {
     {
@@ -217,27 +276,34 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 是否捕获异常
-     * @param bool $boolean
-     * @api
+     * 设置是否捕获异常
+     * @access public
+     * @param bool $boolean 是否捕获
+     * @return $this
      */
      */
     public function setCatchExceptions($boolean)
     public function setCatchExceptions($boolean)
     {
     {
         $this->catchExceptions = (bool) $boolean;
         $this->catchExceptions = (bool) $boolean;
+
+        return $this;
     }
     }
 
 
     /**
     /**
-     * 是否自动退出
-     * @param bool $boolean
-     * @api
+     * 设置是否自动退出
+     * @access public
+     * @param bool $boolean 是否自动退出
+     * @return $this
      */
      */
     public function setAutoExit($boolean)
     public function setAutoExit($boolean)
     {
     {
         $this->autoExit = (bool) $boolean;
         $this->autoExit = (bool) $boolean;
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 获取名称
      * 获取名称
+     * @access public
      * @return string
      * @return string
      */
      */
     public function getName()
     public function getName()
@@ -247,17 +313,21 @@ class Console
 
 
     /**
     /**
      * 设置名称
      * 设置名称
-     * @param string $name
+     * @access public
+     * @param  string $name 名称
+     * @return $this
      */
      */
     public function setName($name)
     public function setName($name)
     {
     {
         $this->name = $name;
         $this->name = $name;
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 获取版本
      * 获取版本
+     * @access public
      * @return string
      * @return string
-     * @api
      */
      */
     public function getVersion()
     public function getVersion()
     {
     {
@@ -266,21 +336,30 @@ class Console
 
 
     /**
     /**
      * 设置版本
      * 设置版本
-     * @param string $version
+     * @access public
+     * @param  string $version 版本信息
+     * @return $this
      */
      */
     public function setVersion($version)
     public function setVersion($version)
     {
     {
         $this->version = $version;
         $this->version = $version;
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 获取完整的版本号
      * 获取完整的版本号
+     * @access public
      * @return string
      * @return string
      */
      */
     public function getLongVersion()
     public function getLongVersion()
     {
     {
         if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
         if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
-            return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
+            return sprintf(
+                '<info>%s</info> version <comment>%s</comment>',
+                $this->getName(),
+                $this->getVersion()
+            );
         }
         }
 
 
         return '<info>Console Tool</info>';
         return '<info>Console Tool</info>';
@@ -288,7 +367,8 @@ class Console
 
 
     /**
     /**
      * 注册一个指令
      * 注册一个指令
-     * @param string $name
+     * @access public
+     * @param string $name 指令名称
      * @return Command
      * @return Command
      */
      */
     public function register($name)
     public function register($name)
@@ -297,32 +377,37 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 添加指令
-     * @param Command[] $commands
+     * 批量添加指令
+     * @access public
+     * @param  Command[] $commands 指令实例
+     * @return $this
      */
      */
     public function addCommands(array $commands)
     public function addCommands(array $commands)
     {
     {
-        foreach ($commands as $command) {
-            $this->add($command);
-        }
+        foreach ($commands as $command) $this->add($command);
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 添加一个指令
      * 添加一个指令
-     * @param Command $command
-     * @return Command
+     * @access public
+     * @param  Command $command 命令实例
+     * @return Command|bool
      */
      */
     public function add(Command $command)
     public function add(Command $command)
     {
     {
-        $command->setConsole($this);
-
         if (!$command->isEnabled()) {
         if (!$command->isEnabled()) {
             $command->setConsole(null);
             $command->setConsole(null);
-            return;
+            return false;
         }
         }
 
 
+        $command->setConsole($this);
+
         if (null === $command->getDefinition()) {
         if (null === $command->getDefinition()) {
-            throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
+            throw new \LogicException(
+                sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))
+            );
         }
         }
 
 
         $this->commands[$command->getName()] = $command;
         $this->commands[$command->getName()] = $command;
@@ -336,14 +421,17 @@ class Console
 
 
     /**
     /**
      * 获取指令
      * 获取指令
-     * @param string $name 指令名称
+     * @access public
+     * @param  string $name 指令名称
      * @return Command
      * @return Command
      * @throws \InvalidArgumentException
      * @throws \InvalidArgumentException
      */
      */
     public function get($name)
     public function get($name)
     {
     {
         if (!isset($this->commands[$name])) {
         if (!isset($this->commands[$name])) {
-            throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
+            throw new \InvalidArgumentException(
+                sprintf('The command "%s" does not exist.', $name)
+            );
         }
         }
 
 
         $command = $this->commands[$name];
         $command = $this->commands[$name];
@@ -363,7 +451,8 @@ class Console
 
 
     /**
     /**
      * 某个指令是否存在
      * 某个指令是否存在
-     * @param string $name 指令名称
+     * @access public
+     * @param  string $name 指令名称
      * @return bool
      * @return bool
      */
      */
     public function has($name)
     public function has($name)
@@ -373,16 +462,22 @@ class Console
 
 
     /**
     /**
      * 获取所有的命名空间
      * 获取所有的命名空间
+     * @access public
      * @return array
      * @return array
      */
      */
     public function getNamespaces()
     public function getNamespaces()
     {
     {
         $namespaces = [];
         $namespaces = [];
+
         foreach ($this->commands as $command) {
         foreach ($this->commands as $command) {
-            $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
+            $namespaces = array_merge(
+                $namespaces, $this->extractAllNamespaces($command->getName())
+            );
 
 
             foreach ($command->getAliases() as $alias) {
             foreach ($command->getAliases() as $alias) {
-                $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
+                $namespaces = array_merge(
+                    $namespaces, $this->extractAllNamespaces($alias)
+                );
             }
             }
         }
         }
 
 
@@ -390,21 +485,25 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 查找注册命名空间中的名称或缩写。
+     * 查找注册命名空间中的名称或缩写
+     * @access public
      * @param string $namespace
      * @param string $namespace
      * @return string
      * @return string
      * @throws \InvalidArgumentException
      * @throws \InvalidArgumentException
      */
      */
     public function findNamespace($namespace)
     public function findNamespace($namespace)
     {
     {
-        $allNamespaces = $this->getNamespaces();
-        $expr          = preg_replace_callback('{([^:]+|)}', function ($matches) {
+        $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
             return preg_quote($matches[1]) . '[^:]*';
             return preg_quote($matches[1]) . '[^:]*';
         }, $namespace);
         }, $namespace);
-        $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);
+
+        $allNamespaces = $this->getNamespaces();
+        $namespaces    = preg_grep('{^' . $expr . '}', $allNamespaces);
 
 
         if (empty($namespaces)) {
         if (empty($namespaces)) {
-            $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
+            $message = sprintf(
+                'There are no commands defined in the "%s" namespace.', $namespace
+            );
 
 
             if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
             if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
                 if (1 == count($alternatives)) {
                 if (1 == count($alternatives)) {
@@ -420,8 +519,14 @@ class Console
         }
         }
 
 
         $exact = in_array($namespace, $namespaces, true);
         $exact = in_array($namespace, $namespaces, true);
+
         if (count($namespaces) > 1 && !$exact) {
         if (count($namespaces) > 1 && !$exact) {
-            throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
+            throw new \InvalidArgumentException(
+                sprintf(
+                    'The namespace "%s" is ambiguous (%s).',
+                    $namespace,
+                    $this->getAbbreviationSuggestions(array_values($namespaces)))
+            );
         }
         }
 
 
         return $exact ? $namespace : reset($namespaces);
         return $exact ? $namespace : reset($namespaces);
@@ -429,20 +534,22 @@ class Console
 
 
     /**
     /**
      * 查找指令
      * 查找指令
-     * @param string $name 名称或者别名
+     * @access public
+     * @param  string $name 名称或者别名
      * @return Command
      * @return Command
      * @throws \InvalidArgumentException
      * @throws \InvalidArgumentException
      */
      */
     public function find($name)
     public function find($name)
     {
     {
-        $allCommands = array_keys($this->commands);
-        $expr        = preg_replace_callback('{([^:]+|)}', function ($matches) {
+        $expr = preg_replace_callback('{([^:]+|)}', function ($matches) {
             return preg_quote($matches[1]) . '[^:]*';
             return preg_quote($matches[1]) . '[^:]*';
         }, $name);
         }, $name);
-        $commands = preg_grep('{^' . $expr . '}', $allCommands);
+
+        $allCommands = array_keys($this->commands);
+        $commands    = preg_grep('{^' . $expr . '}', $allCommands);
 
 
         if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
         if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {
-            if (false !== $pos = strrpos($name, ':')) {
+            if (false !== ($pos = strrpos($name, ':'))) {
                 $this->findNamespace(substr($name, 0, $pos));
                 $this->findNamespace(substr($name, 0, $pos));
             }
             }
 
 
@@ -473,7 +580,9 @@ class Console
         if (count($commands) > 1 && !$exact) {
         if (count($commands) > 1 && !$exact) {
             $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
             $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
 
 
-            throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
+            throw new \InvalidArgumentException(
+                sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)
+            );
         }
         }
 
 
         return $this->get($exact ? $name : reset($commands));
         return $this->get($exact ? $name : reset($commands));
@@ -481,21 +590,20 @@ class Console
 
 
     /**
     /**
      * 获取所有的指令
      * 获取所有的指令
-     * @param string $namespace 命名空间
+     * @access public
+     * @param  string $namespace 命名空间
      * @return Command[]
      * @return Command[]
-     * @api
      */
      */
     public function all($namespace = null)
     public function all($namespace = null)
     {
     {
-        if (null === $namespace) {
-            return $this->commands;
-        }
+        if (null === $namespace) return $this->commands;
 
 
         $commands = [];
         $commands = [];
+
         foreach ($this->commands as $name => $command) {
         foreach ($this->commands as $name => $command) {
-            if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {
-                $commands[$name] = $command;
-            }
+            $ext = $this->extractNamespace($name, substr_count($namespace, ':') + 1);
+
+            if ($ext === $namespace) $commands[$name] = $command;
         }
         }
 
 
         return $commands;
         return $commands;
@@ -503,7 +611,8 @@ class Console
 
 
     /**
     /**
      * 获取可能的指令名
      * 获取可能的指令名
-     * @param array $names
+     * @access public
+     * @param  array $names 指令名
      * @return array
      * @return array
      */
      */
     public static function getAbbreviations($names)
     public static function getAbbreviations($names)
@@ -520,9 +629,11 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 配置基于用户的参数和选项的输入和输出实例。
-     * @param Input  $input  输入实例
-     * @param Output $output 输出实例
+     * 配置基于用户的参数和选项的输入和输出实例
+     * @access protected
+     * @param  Input  $input  输入实例
+     * @param  Output $output 输出实例
+     * @return void
      */
      */
     protected function configureIO(Input $input, Output $output)
     protected function configureIO(Input $input, Output $output)
     {
     {
@@ -551,9 +662,10 @@ class Console
 
 
     /**
     /**
      * 执行指令
      * 执行指令
-     * @param Command $command 指令实例
-     * @param Input   $input   输入实例
-     * @param Output  $output  输出实例
+     * @access protected
+     * @param  Command $command 指令实例
+     * @param  Input   $input   输入实例
+     * @param  Output  $output  输出实例
      * @return int
      * @return int
      * @throws \Exception
      * @throws \Exception
      */
      */
@@ -563,8 +675,9 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 获取指令的基础名称
-     * @param Input $input
+     * 获取指令的名称
+     * @access protected
+     * @param  Input $input 输入实例
      * @return string
      * @return string
      */
      */
     protected function getCommandName(Input $input)
     protected function getCommandName(Input $input)
@@ -574,6 +687,7 @@ class Console
 
 
     /**
     /**
      * 获取默认输入定义
      * 获取默认输入定义
+     * @access protected
      * @return InputDefinition
      * @return InputDefinition
      */
      */
     protected function getDefaultInputDefinition()
     protected function getDefaultInputDefinition()
@@ -591,41 +705,55 @@ class Console
     }
     }
 
 
     /**
     /**
-     * 设置默认命令
-     * @return Command[] An array of default Command instances
+     * 获取默认命令
+     * @access protected
+     * @return Command[]
      */
      */
     protected function getDefaultCommands()
     protected function getDefaultCommands()
     {
     {
         $defaultCommands = [];
         $defaultCommands = [];
 
 
-        foreach (self::$defaultCommands as $classname) {
-            if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) {
-                $defaultCommands[] = new $classname();
+        foreach (self::$defaultCommands as $class) {
+            if (class_exists($class) && is_subclass_of($class, "think\\console\\Command")) {
+                $defaultCommands[] = new $class();
             }
             }
         }
         }
 
 
         return $defaultCommands;
         return $defaultCommands;
     }
     }
 
 
-    public static function addDefaultCommands(array $classnames)
+    /**
+     * 添加默认指令
+     * @access public
+     * @param  array $classes 指令
+     * @return void
+     */
+    public static function addDefaultCommands(array $classes)
     {
     {
-        self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);
+        self::$defaultCommands = array_merge(self::$defaultCommands, $classes);
     }
     }
 
 
     /**
     /**
      * 获取可能的建议
      * 获取可能的建议
-     * @param array $abbrevs
+     * @access private
+     * @param  array $abbrevs
      * @return string
      * @return string
      */
      */
     private function getAbbreviationSuggestions($abbrevs)
     private function getAbbreviationSuggestions($abbrevs)
     {
     {
-        return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
+        return sprintf(
+            '%s, %s%s',
+            $abbrevs[0],
+            $abbrevs[1],
+            count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''
+        );
     }
     }
 
 
     /**
     /**
-     * 返回命名空间部分
-     * @param string $name  指令
-     * @param string $limit 部分的命名空间的最大数量
+     * 返回指令的命名空间部分
+     * @access public
+     * @param  string $name  指令名称
+     * @param  string $limit 部分的命名空间的最大数量
      * @return string
      * @return string
      */
      */
     public function extractNamespace($name, $limit = null)
     public function extractNamespace($name, $limit = null)
@@ -638,16 +766,17 @@ class Console
 
 
     /**
     /**
      * 查找可替代的建议
      * 查找可替代的建议
-     * @param string             $name
-     * @param array|\Traversable $collection
+     * @access private
+     * @param string             $name       指令名称
+     * @param array|\Traversable $collection 建议集合
      * @return array
      * @return array
      */
      */
     private function findAlternatives($name, $collection)
     private function findAlternatives($name, $collection)
     {
     {
-        $threshold    = 1e3;
-        $alternatives = [];
-
+        $threshold       = 1e3;
+        $alternatives    = [];
         $collectionParts = [];
         $collectionParts = [];
+
         foreach ($collection as $item) {
         foreach ($collection as $item) {
             $collectionParts[$item] = explode(':', $item);
             $collectionParts[$item] = explode(':', $item);
         }
         }
@@ -655,6 +784,7 @@ class Console
         foreach (explode(':', $name) as $i => $subname) {
         foreach (explode(':', $name) as $i => $subname) {
             foreach ($collectionParts as $collectionName => $parts) {
             foreach ($collectionParts as $collectionName => $parts) {
                 $exists = isset($alternatives[$collectionName]);
                 $exists = isset($alternatives[$collectionName]);
+
                 if (!isset($parts[$i]) && $exists) {
                 if (!isset($parts[$i]) && $exists) {
                     $alternatives[$collectionName] += $threshold;
                     $alternatives[$collectionName] += $threshold;
                     continue;
                     continue;
@@ -663,8 +793,14 @@ class Console
                 }
                 }
 
 
                 $lev = levenshtein($subname, $parts[$i]);
                 $lev = levenshtein($subname, $parts[$i]);
-                if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
-                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
+
+                if ($lev <= strlen($subname) / 3 ||
+                    '' !== $subname &&
+                    false !== strpos($parts[$i], $subname)
+                ) {
+                    $alternatives[$collectionName] = $exists ?
+                        $alternatives[$collectionName] + $lev :
+                        $lev;
                 } elseif ($exists) {
                 } elseif ($exists) {
                     $alternatives[$collectionName] += $threshold;
                     $alternatives[$collectionName] += $threshold;
                 }
                 }
@@ -673,14 +809,18 @@ class Console
 
 
         foreach ($collection as $item) {
         foreach ($collection as $item) {
             $lev = levenshtein($name, $item);
             $lev = levenshtein($name, $item);
+
             if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
             if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
-                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
+                $alternatives[$item] = isset($alternatives[$item]) ?
+                    $alternatives[$item] - $lev :
+                    $lev;
             }
             }
         }
         }
 
 
         $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
         $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {
             return $lev < 2 * $threshold;
             return $lev < 2 * $threshold;
         });
         });
+
         asort($alternatives);
         asort($alternatives);
 
 
         return array_keys($alternatives);
         return array_keys($alternatives);
@@ -688,24 +828,28 @@ class Console
 
 
     /**
     /**
      * 设置默认的指令
      * 设置默认的指令
-     * @param string $commandName The Command name
+     * @access public
+     * @param string $commandName 指令名称
+     * @return $this
      */
      */
     public function setDefaultCommand($commandName)
     public function setDefaultCommand($commandName)
     {
     {
         $this->defaultCommand = $commandName;
         $this->defaultCommand = $commandName;
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 返回所有的命名空间
      * 返回所有的命名空间
-     * @param string $name
+     * @access private
+     * @param  string $name 指令名称
      * @return array
      * @return array
      */
      */
     private function extractAllNamespaces($name)
     private function extractAllNamespaces($name)
     {
     {
-        $parts      = explode(':', $name, -1);
         $namespaces = [];
         $namespaces = [];
 
 
-        foreach ($parts as $part) {
+        foreach (explode(':', $name, -1) as $part) {
             if (count($namespaces)) {
             if (count($namespaces)) {
                 $namespaces[] = end($namespaces) . ':' . $part;
                 $namespaces[] = end($namespaces) . ':' . $part;
             } else {
             } else {

+ 57 - 41
thinkphp/library/think/Controller.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -24,34 +24,36 @@ class Controller
      * @var \think\View 视图类实例
      * @var \think\View 视图类实例
      */
      */
     protected $view;
     protected $view;
+
     /**
     /**
-     * @var \think\Request Request实例
+     * @var \think\Request Request 实例
      */
      */
     protected $request;
     protected $request;
-    // 验证失败是否抛出异常
+
+    /**
+     * @var bool 验证失败是否抛出异常
+     */
     protected $failException = false;
     protected $failException = false;
-    // 是否批量验证
+
+    /**
+     * @var bool 是否批量验证
+     */
     protected $batchValidate = false;
     protected $batchValidate = false;
 
 
     /**
     /**
-     * 前置操作方法列表
-     * @var array $beforeActionList
-     * @access protected
+     * @var array 前置操作方法列表
      */
      */
     protected $beforeActionList = [];
     protected $beforeActionList = [];
 
 
     /**
     /**
      * 构造方法
      * 构造方法
-     * @param Request $request Request对象
      * @access public
      * @access public
+     * @param Request $request Request 对象
      */
      */
     public function __construct(Request $request = null)
     public function __construct(Request $request = null)
     {
     {
-        if (is_null($request)) {
-            $request = Request::instance();
-        }
         $this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));
         $this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));
-        $this->request = $request;
+        $this->request = is_null($request) ? Request::instance() : $request;
 
 
         // 控制器初始化
         // 控制器初始化
         $this->_initialize();
         $this->_initialize();
@@ -66,7 +68,10 @@ class Controller
         }
         }
     }
     }
 
 
-    // 初始化
+    /**
+     * 初始化操作
+     * @access protected
+     */
     protected function _initialize()
     protected function _initialize()
     {
     {
     }
     }
@@ -74,8 +79,9 @@ class Controller
     /**
     /**
      * 前置操作
      * 前置操作
      * @access protected
      * @access protected
-     * @param string $method  前置操作方法名
-     * @param array  $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]
+     * @param  string $method  前置操作方法名
+     * @param  array  $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
+     * @return void
      */
      */
     protected function beforeAction($method, $options = [])
     protected function beforeAction($method, $options = [])
     {
     {
@@ -83,6 +89,7 @@ class Controller
             if (is_string($options['only'])) {
             if (is_string($options['only'])) {
                 $options['only'] = explode(',', $options['only']);
                 $options['only'] = explode(',', $options['only']);
             }
             }
+
             if (!in_array($this->request->action(), $options['only'])) {
             if (!in_array($this->request->action(), $options['only'])) {
                 return;
                 return;
             }
             }
@@ -90,6 +97,7 @@ class Controller
             if (is_string($options['except'])) {
             if (is_string($options['except'])) {
                 $options['except'] = explode(',', $options['except']);
                 $options['except'] = explode(',', $options['except']);
             }
             }
+
             if (in_array($this->request->action(), $options['except'])) {
             if (in_array($this->request->action(), $options['except'])) {
                 return;
                 return;
             }
             }
@@ -101,10 +109,10 @@ class Controller
     /**
     /**
      * 加载模板输出
      * 加载模板输出
      * @access protected
      * @access protected
-     * @param string $template 模板文件名
-     * @param array  $vars     模板输出变量
-     * @param array  $replace  模板替换
-     * @param array  $config   模板参数
+     * @param  string $template 模板文件名
+     * @param  array  $vars     模板输出变量
+     * @param  array  $replace  模板替换
+     * @param  array  $config   模板参数
      * @return mixed
      * @return mixed
      */
      */
     protected function fetch($template = '', $vars = [], $replace = [], $config = [])
     protected function fetch($template = '', $vars = [], $replace = [], $config = [])
@@ -115,10 +123,10 @@ class Controller
     /**
     /**
      * 渲染内容输出
      * 渲染内容输出
      * @access protected
      * @access protected
-     * @param string $content 模板内容
-     * @param array  $vars    模板输出变量
-     * @param array  $replace 替换内容
-     * @param array  $config  模板参数
+     * @param  string $content 模板内容
+     * @param  array  $vars    模板输出变量
+     * @param  array  $replace 替换内容
+     * @param  array  $config  模板参数
      * @return mixed
      * @return mixed
      */
      */
     protected function display($content = '', $vars = [], $replace = [], $config = [])
     protected function display($content = '', $vars = [], $replace = [], $config = [])
@@ -129,24 +137,28 @@ class Controller
     /**
     /**
      * 模板变量赋值
      * 模板变量赋值
      * @access protected
      * @access protected
-     * @param mixed $name  要显示的模板变量
-     * @param mixed $value 变量的值
-     * @return void
+     * @param  mixed $name  要显示的模板变量
+     * @param  mixed $value 变量的值
+     * @return $this
      */
      */
     protected function assign($name, $value = '')
     protected function assign($name, $value = '')
     {
     {
         $this->view->assign($name, $value);
         $this->view->assign($name, $value);
+
+        return $this;
     }
     }
 
 
     /**
     /**
      * 初始化模板引擎
      * 初始化模板引擎
      * @access protected
      * @access protected
      * @param array|string $engine 引擎参数
      * @param array|string $engine 引擎参数
-     * @return void
+     * @return $this
      */
      */
     protected function engine($engine)
     protected function engine($engine)
     {
     {
         $this->view->engine($engine);
         $this->view->engine($engine);
+
+        return $this;
     }
     }
 
 
     /**
     /**
@@ -158,17 +170,18 @@ class Controller
     protected function validateFailException($fail = true)
     protected function validateFailException($fail = true)
     {
     {
         $this->failException = $fail;
         $this->failException = $fail;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 验证数据
      * 验证数据
      * @access protected
      * @access protected
-     * @param array        $data     数据
-     * @param string|array $validate 验证器名或者验证规则数组
-     * @param array        $message  提示信息
-     * @param bool         $batch    是否批量验证
-     * @param mixed        $callback 回调方法(闭包)
+     * @param  array        $data     数据
+     * @param  string|array $validate 验证器名或者验证规则数组
+     * @param  array        $message  提示信息
+     * @param  bool         $batch    是否批量验证
+     * @param  mixed        $callback 回调方法(闭包)
      * @return array|string|true
      * @return array|string|true
      * @throws ValidateException
      * @throws ValidateException
      */
      */
@@ -178,24 +191,27 @@ class Controller
             $v = Loader::validate();
             $v = Loader::validate();
             $v->rule($validate);
             $v->rule($validate);
         } else {
         } else {
+            // 支持场景
             if (strpos($validate, '.')) {
             if (strpos($validate, '.')) {
-                // 支持场景
                 list($validate, $scene) = explode('.', $validate);
                 list($validate, $scene) = explode('.', $validate);
             }
             }
+
             $v = Loader::validate($validate);
             $v = Loader::validate($validate);
-            if (!empty($scene)) {
-                $v->scene($scene);
-            }
+
+            !empty($scene) && $v->scene($scene);
         }
         }
-        // 是否批量验证
+
+        // 批量验证
         if ($batch || $this->batchValidate) {
         if ($batch || $this->batchValidate) {
             $v->batch(true);
             $v->batch(true);
         }
         }
 
 
+        // 设置错误信息
         if (is_array($message)) {
         if (is_array($message)) {
             $v->message($message);
             $v->message($message);
         }
         }
 
 
+        // 使用回调验证
         if ($callback && is_callable($callback)) {
         if ($callback && is_callable($callback)) {
             call_user_func_array($callback, [$v, &$data]);
             call_user_func_array($callback, [$v, &$data]);
         }
         }
@@ -203,11 +219,11 @@ class Controller
         if (!$v->check($data)) {
         if (!$v->check($data)) {
             if ($this->failException) {
             if ($this->failException) {
                 throw new ValidateException($v->getError());
                 throw new ValidateException($v->getError());
-            } else {
-                return $v->getError();
             }
             }
-        } else {
-            return true;
+
+            return $v->getError();
         }
         }
+
+        return true;
     }
     }
 }
 }

+ 104 - 60
thinkphp/library/think/Cookie.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -13,28 +13,28 @@ namespace think;
 
 
 class Cookie
 class Cookie
 {
 {
+    /**
+     * @var array cookie 设置参数
+     */
     protected static $config = [
     protected static $config = [
-        // cookie 名称前缀
-        'prefix'    => '',
-        // cookie 保存时间
-        'expire'    => 0,
-        // cookie 保存路径
-        'path'      => '/',
-        // cookie 有效域名
-        'domain'    => '',
-        //  cookie 启用安全传输
-        'secure'    => false,
-        // httponly设置
-        'httponly'  => '',
-        // 是否使用 setcookie
-        'setcookie' => true,
+        'prefix'    => '', // cookie 名称前缀
+        'expire'    => 0, // cookie 保存时间
+        'path'      => '/', // cookie 保存路径
+        'domain'    => '', // cookie 有效域名
+        'secure'    => false, //  cookie 启用安全传输
+        'httponly'  => false, // httponly 设置
+        'setcookie' => true, // 是否使用 setcookie
     ];
     ];
 
 
+    /**
+     * @var bool 是否完成初始化了
+     */
     protected static $init;
     protected static $init;
 
 
     /**
     /**
      * Cookie初始化
      * Cookie初始化
-     * @param array $config
+     * @access public
+     * @param  array $config 配置参数
      * @return void
      * @return void
      */
      */
     public static function init(array $config = [])
     public static function init(array $config = [])
@@ -42,39 +42,43 @@ class Cookie
         if (empty($config)) {
         if (empty($config)) {
             $config = Config::get('cookie');
             $config = Config::get('cookie');
         }
         }
+
         self::$config = array_merge(self::$config, array_change_key_case($config));
         self::$config = array_merge(self::$config, array_change_key_case($config));
+
         if (!empty(self::$config['httponly'])) {
         if (!empty(self::$config['httponly'])) {
             ini_set('session.cookie_httponly', 1);
             ini_set('session.cookie_httponly', 1);
         }
         }
+
         self::$init = true;
         self::$init = true;
     }
     }
 
 
     /**
     /**
-     * 设置或者获取cookie作用域(前缀)
-     * @param string $prefix
-     * @return string|void
+     * 设置或者获取 cookie 作用域(前缀)
+     * @access public
+     * @param  string $prefix 前缀
+     * @return string|
      */
      */
     public static function prefix($prefix = '')
     public static function prefix($prefix = '')
     {
     {
         if (empty($prefix)) {
         if (empty($prefix)) {
             return self::$config['prefix'];
             return self::$config['prefix'];
         }
         }
-        self::$config['prefix'] = $prefix;
+
+        return self::$config['prefix'] = $prefix;
     }
     }
 
 
     /**
     /**
      * Cookie 设置、获取、删除
      * Cookie 设置、获取、删除
-     *
-     * @param string $name  cookie名称
-     * @param mixed  $value cookie值
-     * @param mixed  $option 可选参数 可能会是 null|integer|string
-     *
-     * @return mixed
-     * @internal param mixed $options cookie参数
+     * @access public
+     * @param  string $name   cookie 名称
+     * @param  mixed  $value  cookie 值
+     * @param  mixed  $option 可选参数 可能会是 null|integer|string
+     * @return void
      */
      */
     public static function set($name, $value = '', $option = null)
     public static function set($name, $value = '', $option = null)
     {
     {
         !isset(self::$init) && self::init();
         !isset(self::$init) && self::init();
+
         // 参数设置(会覆盖黙认设置)
         // 参数设置(会覆盖黙认设置)
         if (!is_null($option)) {
         if (!is_null($option)) {
             if (is_numeric($option)) {
             if (is_numeric($option)) {
@@ -82,28 +86,40 @@ class Cookie
             } elseif (is_string($option)) {
             } elseif (is_string($option)) {
                 parse_str($option, $option);
                 parse_str($option, $option);
             }
             }
+
             $config = array_merge(self::$config, array_change_key_case($option));
             $config = array_merge(self::$config, array_change_key_case($option));
         } else {
         } else {
             $config = self::$config;
             $config = self::$config;
         }
         }
+
         $name = $config['prefix'] . $name;
         $name = $config['prefix'] . $name;
-        // 设置cookie
+
+        // 设置 cookie
         if (is_array($value)) {
         if (is_array($value)) {
             array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');
             array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');
             $value = 'think:' . json_encode($value);
             $value = 'think:' . json_encode($value);
         }
         }
-        $expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
+
+        $expire = !empty($config['expire']) ?
+        $_SERVER['REQUEST_TIME'] + intval($config['expire']) :
+        0;
+
         if ($config['setcookie']) {
         if ($config['setcookie']) {
-            setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+            setcookie(
+                $name, $value, $expire, $config['path'], $config['domain'],
+                $config['secure'], $config['httponly']
+            );
         }
         }
+
         $_COOKIE[$name] = $value;
         $_COOKIE[$name] = $value;
     }
     }
 
 
     /**
     /**
-     * 永久保存Cookie数据
-     * @param string $name  cookie名称
-     * @param mixed  $value cookie值
-     * @param mixed  $option 可选参数 可能会是 null|integer|string
+     * 永久保存 Cookie 数据
+     * @access public
+     * @param  string $name   cookie 名称
+     * @param  mixed  $value  cookie 值
+     * @param  mixed  $option 可选参数 可能会是 null|integer|string
      * @return void
      * @return void
      */
      */
     public static function forever($name, $value = '', $option = null)
     public static function forever($name, $value = '', $option = null)
@@ -111,33 +127,39 @@ class Cookie
         if (is_null($option) || is_numeric($option)) {
         if (is_null($option) || is_numeric($option)) {
             $option = [];
             $option = [];
         }
         }
+
         $option['expire'] = 315360000;
         $option['expire'] = 315360000;
+
         self::set($name, $value, $option);
         self::set($name, $value, $option);
     }
     }
 
 
     /**
     /**
-     * 判断Cookie数据
-     * @param string        $name cookie名称
-     * @param string|null   $prefix cookie前缀
+     * 判断是否有 Cookie 数据
+     * @access public
+     * @param  string      $name   cookie 名称
+     * @param  string|null $prefix cookie 前缀
      * @return bool
      * @return bool
      */
      */
     public static function has($name, $prefix = null)
     public static function has($name, $prefix = null)
     {
     {
         !isset(self::$init) && self::init();
         !isset(self::$init) && self::init();
+
         $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
         $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
-        $name   = $prefix . $name;
-        return isset($_COOKIE[$name]);
+
+        return isset($_COOKIE[$prefix . $name]);
     }
     }
 
 
     /**
     /**
-     * Cookie获取
-     * @param string        $name cookie名称
-     * @param string|null   $prefix cookie前缀
+     * 获取 Cookie 的值
+     * @access public
+     * @param string      $name   cookie 名称
+     * @param string|null $prefix cookie 前缀
      * @return mixed
      * @return mixed
      */
      */
     public static function get($name = '', $prefix = null)
     public static function get($name = '', $prefix = null)
     {
     {
         !isset(self::$init) && self::init();
         !isset(self::$init) && self::init();
+
         $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
         $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];
         $key    = $prefix . $name;
         $key    = $prefix . $name;
 
 
@@ -145,80 +167,102 @@ class Cookie
             // 获取全部
             // 获取全部
             if ($prefix) {
             if ($prefix) {
                 $value = [];
                 $value = [];
+
                 foreach ($_COOKIE as $k => $val) {
                 foreach ($_COOKIE as $k => $val) {
                     if (0 === strpos($k, $prefix)) {
                     if (0 === strpos($k, $prefix)) {
                         $value[$k] = $val;
                         $value[$k] = $val;
                     }
                     }
+
                 }
                 }
             } else {
             } else {
                 $value = $_COOKIE;
                 $value = $_COOKIE;
             }
             }
         } elseif (isset($_COOKIE[$key])) {
         } elseif (isset($_COOKIE[$key])) {
             $value = $_COOKIE[$key];
             $value = $_COOKIE[$key];
+
             if (0 === strpos($value, 'think:')) {
             if (0 === strpos($value, 'think:')) {
-                $value = substr($value, 6);
-                $value = json_decode($value, true);
+                $value = json_decode(substr($value, 6), true);
                 array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
                 array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');
             }
             }
         } else {
         } else {
             $value = null;
             $value = null;
         }
         }
+
         return $value;
         return $value;
     }
     }
 
 
     /**
     /**
-     * Cookie删除
-     * @param string        $name cookie名称
-     * @param string|null   $prefix cookie前缀
-     * @return mixed
+     * 删除 Cookie
+     * @access public
+     * @param  string      $name   cookie 名称
+     * @param  string|null $prefix cookie 前缀
+     * @return void
      */
      */
     public static function delete($name, $prefix = null)
     public static function delete($name, $prefix = null)
     {
     {
         !isset(self::$init) && self::init();
         !isset(self::$init) && self::init();
+
         $config = self::$config;
         $config = self::$config;
         $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
         $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
         $name   = $prefix . $name;
         $name   = $prefix . $name;
+
         if ($config['setcookie']) {
         if ($config['setcookie']) {
-            setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+            setcookie(
+                $name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'],
+                $config['domain'], $config['secure'], $config['httponly']
+            );
         }
         }
-        // 删除指定cookie
+
+        // 删除指定 cookie
         unset($_COOKIE[$name]);
         unset($_COOKIE[$name]);
     }
     }
 
 
     /**
     /**
-     * Cookie清空
-     * @param string|null $prefix cookie前缀
-     * @return mixed
+     * 清除指定前缀的所有 cookie
+     * @access public
+     * @param  string|null $prefix cookie 前缀
+     * @return void
      */
      */
     public static function clear($prefix = null)
     public static function clear($prefix = null)
     {
     {
-        // 清除指定前缀的所有cookie
         if (empty($_COOKIE)) {
         if (empty($_COOKIE)) {
             return;
             return;
         }
         }
+
         !isset(self::$init) && self::init();
         !isset(self::$init) && self::init();
-        // 要删除的cookie前缀,不指定则删除config设置的指定前缀
+
+        // 要删除的 cookie 前缀,不指定则删除 config 设置的指定前缀
         $config = self::$config;
         $config = self::$config;
         $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
         $prefix = !is_null($prefix) ? $prefix : $config['prefix'];
+
         if ($prefix) {
         if ($prefix) {
-            // 如果前缀为空字符串将不作处理直接返回
             foreach ($_COOKIE as $key => $val) {
             foreach ($_COOKIE as $key => $val) {
                 if (0 === strpos($key, $prefix)) {
                 if (0 === strpos($key, $prefix)) {
                     if ($config['setcookie']) {
                     if ($config['setcookie']) {
-                        setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
+                        setcookie(
+                            $key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'],
+                            $config['domain'], $config['secure'], $config['httponly']
+                        );
                     }
                     }
+
                     unset($_COOKIE[$key]);
                     unset($_COOKIE[$key]);
                 }
                 }
             }
             }
         }
         }
-        return;
     }
     }
 
 
-    private static function jsonFormatProtect(&$val, $key, $type = 'encode')
+    /**
+     * json 转换时的格式保护
+     * @access protected
+     * @param  mixed  $val  要转换的值
+     * @param  string $key  键名
+     * @param  string $type 转换类别
+     * @return void
+     */
+    protected static function jsonFormatProtect(&$val, $key, $type = 'encode')
     {
     {
         if (!empty($val) && true !== $val) {
         if (!empty($val) && true !== $val) {
             $val = 'decode' == $type ? urldecode($val) : urlencode($val);
             $val = 'decode' == $type ? urldecode($val) : urlencode($val);
         }
         }
     }
     }
-
 }
 }

+ 50 - 26
thinkphp/library/think/Db.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -49,19 +49,26 @@ use think\db\Query;
  */
  */
 class Db
 class Db
 {
 {
-    //  数据库连接实例
+    /**
+     * @var Connection[] 数据库连接实例
+     */
     private static $instance = [];
     private static $instance = [];
-    // 查询次数
+
+    /**
+     * @var int 查询次数
+     */
     public static $queryTimes = 0;
     public static $queryTimes = 0;
-    // 执行次数
+
+    /**
+     * @var int 执行次数
+     */
     public static $executeTimes = 0;
     public static $executeTimes = 0;
 
 
     /**
     /**
-     * 数据库初始化 并取得数据库类实例
-     * @static
+     * 数据库初始化,并取得数据库类实例
      * @access public
      * @access public
-     * @param mixed         $config 连接配置
-     * @param bool|string   $name 连接标识 true 强制重新连接
+     * @param  mixed       $config 连接配置
+     * @param  bool|string $name   连接标识 true 强制重新连接
      * @return Connection
      * @return Connection
      * @throws Exception
      * @throws Exception
      */
      */
@@ -70,34 +77,48 @@ class Db
         if (false === $name) {
         if (false === $name) {
             $name = md5(serialize($config));
             $name = md5(serialize($config));
         }
         }
+
         if (true === $name || !isset(self::$instance[$name])) {
         if (true === $name || !isset(self::$instance[$name])) {
             // 解析连接参数 支持数组和字符串
             // 解析连接参数 支持数组和字符串
             $options = self::parseConfig($config);
             $options = self::parseConfig($config);
+
             if (empty($options['type'])) {
             if (empty($options['type'])) {
                 throw new \InvalidArgumentException('Undefined db type');
                 throw new \InvalidArgumentException('Undefined db type');
             }
             }
-            $class = false !== strpos($options['type'], '\\') ? $options['type'] : '\\think\\db\\connector\\' . ucwords($options['type']);
+
+            $class = false !== strpos($options['type'], '\\') ?
+            $options['type'] :
+            '\\think\\db\\connector\\' . ucwords($options['type']);
+
             // 记录初始化信息
             // 记录初始化信息
             if (App::$debug) {
             if (App::$debug) {
                 Log::record('[ DB ] INIT ' . $options['type'], 'info');
                 Log::record('[ DB ] INIT ' . $options['type'], 'info');
             }
             }
+
             if (true === $name) {
             if (true === $name) {
                 $name = md5(serialize($config));
                 $name = md5(serialize($config));
             }
             }
+
             self::$instance[$name] = new $class($options);
             self::$instance[$name] = new $class($options);
         }
         }
+
         return self::$instance[$name];
         return self::$instance[$name];
     }
     }
-    
-    public static function clear() {
-        self::$instance = null;
+
+    /**
+     * 清除连接实例
+     * @access public
+     * @return void
+     */
+    public static function clear()
+    {
+        self::$instance = [];
     }
     }
 
 
     /**
     /**
      * 数据库连接参数解析
      * 数据库连接参数解析
-     * @static
      * @access private
      * @access private
-     * @param mixed $config
+     * @param  mixed $config 连接参数
      * @return array
      * @return array
      */
      */
     private static function parseConfig($config)
     private static function parseConfig($config)
@@ -105,30 +126,27 @@ class Db
         if (empty($config)) {
         if (empty($config)) {
             $config = Config::get('database');
             $config = Config::get('database');
         } elseif (is_string($config) && false === strpos($config, '/')) {
         } elseif (is_string($config) && false === strpos($config, '/')) {
-            // 支持读取配置参数
-            $config = Config::get($config);
-        }
-        if (is_string($config)) {
-            return self::parseDsn($config);
-        } else {
-            return $config;
+            $config = Config::get($config); // 支持读取配置参数
         }
         }
+
+        return is_string($config) ? self::parseDsn($config) : $config;
     }
     }
 
 
     /**
     /**
-     * DSN解析
+     * DSN 解析
      * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8
      * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8
-     * @static
      * @access private
      * @access private
-     * @param string $dsnStr
+     * @param  string $dsnStr 数据库 DSN 字符串解析
      * @return array
      * @return array
      */
      */
     private static function parseDsn($dsnStr)
     private static function parseDsn($dsnStr)
     {
     {
         $info = parse_url($dsnStr);
         $info = parse_url($dsnStr);
+
         if (!$info) {
         if (!$info) {
             return [];
             return [];
         }
         }
+
         $dsn = [
         $dsn = [
             'type'     => $info['scheme'],
             'type'     => $info['scheme'],
             'username' => isset($info['user']) ? $info['user'] : '',
             'username' => isset($info['user']) ? $info['user'] : '',
@@ -144,13 +162,19 @@ class Db
         } else {
         } else {
             $dsn['params'] = [];
             $dsn['params'] = [];
         }
         }
+
         return $dsn;
         return $dsn;
     }
     }
 
 
-    // 调用驱动类的方法
+    /**
+     * 调用驱动类的方法
+     * @access public
+     * @param  string $method 方法名
+     * @param  array  $params 参数
+     * @return mixed
+     */
     public static function __callStatic($method, $params)
     public static function __callStatic($method, $params)
     {
     {
-        // 自动初始化数据库
         return call_user_func_array([self::connect(), $method], $params);
         return call_user_func_array([self::connect(), $method], $params);
     }
     }
 }
 }

+ 84 - 44
thinkphp/library/think/Debug.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -16,21 +16,27 @@ use think\response\Redirect;
 
 
 class Debug
 class Debug
 {
 {
-    // 区间时间信息
+    /**
+     * @var array 区间时间信息
+     */
     protected static $info = [];
     protected static $info = [];
-    // 区间内存信息
+
+    /**
+     * @var array 区间内存信息
+     */
     protected static $mem = [];
     protected static $mem = [];
 
 
     /**
     /**
      * 记录时间(微秒)和内存使用情况
      * 记录时间(微秒)和内存使用情况
-     * @param string    $name 标记位置
-     * @param mixed     $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存
-     * @return mixed
+     * @access public
+     * @param  string $name  标记位置
+     * @param  mixed  $value 标记值(留空则取当前 time 表示仅记录时间 否则同时记录时间和内存)
+     * @return void
      */
      */
     public static function remark($name, $value = '')
     public static function remark($name, $value = '')
     {
     {
-        // 记录时间和内存使用
         self::$info[$name] = is_float($value) ? $value : microtime(true);
         self::$info[$name] = is_float($value) ? $value : microtime(true);
+
         if ('time' != $value) {
         if ('time' != $value) {
             self::$mem['mem'][$name]  = is_float($value) ? $value : memory_get_usage();
             self::$mem['mem'][$name]  = is_float($value) ? $value : memory_get_usage();
             self::$mem['peak'][$name] = memory_get_peak_usage();
             self::$mem['peak'][$name] = memory_get_peak_usage();
@@ -39,23 +45,26 @@ class Debug
 
 
     /**
     /**
      * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
      * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
-     * @param string            $start 开始标签
-     * @param string            $end 结束标签
-     * @param integer|string    $dec 小数位
-     * @return integer
+     * @access public
+     * @param  string  $start 开始标签
+     * @param  string  $end   结束标签
+     * @param  integer $dec   小数位
+     * @return string
      */
      */
     public static function getRangeTime($start, $end, $dec = 6)
     public static function getRangeTime($start, $end, $dec = 6)
     {
     {
         if (!isset(self::$info[$end])) {
         if (!isset(self::$info[$end])) {
             self::$info[$end] = microtime(true);
             self::$info[$end] = microtime(true);
         }
         }
+
         return number_format((self::$info[$end] - self::$info[$start]), $dec);
         return number_format((self::$info[$end] - self::$info[$start]), $dec);
     }
     }
 
 
     /**
     /**
      * 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
      * 统计从开始到统计时的时间(微秒)使用情况 返回值以秒为单位
-     * @param integer|string $dec 小数位
-     * @return integer
+     * @access public
+     * @param  integer $dec 小数位
+     * @return string
      */
      */
     public static function getUseTime($dec = 6)
     public static function getUseTime($dec = 6)
     {
     {
@@ -64,6 +73,7 @@ class Debug
 
 
     /**
     /**
      * 获取当前访问的吞吐率情况
      * 获取当前访问的吞吐率情况
+     * @access public
      * @return string
      * @return string
      */
      */
     public static function getThroughputRate()
     public static function getThroughputRate()
@@ -73,9 +83,10 @@ class Debug
 
 
     /**
     /**
      * 记录区间的内存使用情况
      * 记录区间的内存使用情况
-     * @param string            $start 开始标签
-     * @param string            $end 结束标签
-     * @param integer|string    $dec 小数位
+     * @access public
+     * @param  string  $start 开始标签
+     * @param  string  $end   结束标签
+     * @param  integer $dec   小数位
      * @return string
      * @return string
      */
      */
     public static function getRangeMem($start, $end, $dec = 2)
     public static function getRangeMem($start, $end, $dec = 2)
@@ -83,19 +94,23 @@ class Debug
         if (!isset(self::$mem['mem'][$end])) {
         if (!isset(self::$mem['mem'][$end])) {
             self::$mem['mem'][$end] = memory_get_usage();
             self::$mem['mem'][$end] = memory_get_usage();
         }
         }
+
         $size = self::$mem['mem'][$end] - self::$mem['mem'][$start];
         $size = self::$mem['mem'][$end] - self::$mem['mem'][$start];
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $pos  = 0;
         $pos  = 0;
+
         while ($size >= 1024) {
         while ($size >= 1024) {
             $size /= 1024;
             $size /= 1024;
             $pos++;
             $pos++;
         }
         }
+
         return round($size, $dec) . " " . $a[$pos];
         return round($size, $dec) . " " . $a[$pos];
     }
     }
 
 
     /**
     /**
      * 统计从开始到统计时的内存使用情况
      * 统计从开始到统计时的内存使用情况
-     * @param integer|string $dec 小数位
+     * @access public
+     * @param  integer $dec 小数位
      * @return string
      * @return string
      */
      */
     public static function getUseMem($dec = 2)
     public static function getUseMem($dec = 2)
@@ -103,103 +118,128 @@ class Debug
         $size = memory_get_usage() - THINK_START_MEM;
         $size = memory_get_usage() - THINK_START_MEM;
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $pos  = 0;
         $pos  = 0;
+
         while ($size >= 1024) {
         while ($size >= 1024) {
             $size /= 1024;
             $size /= 1024;
             $pos++;
             $pos++;
         }
         }
+
         return round($size, $dec) . " " . $a[$pos];
         return round($size, $dec) . " " . $a[$pos];
     }
     }
 
 
     /**
     /**
      * 统计区间的内存峰值情况
      * 统计区间的内存峰值情况
-     * @param string            $start 开始标签
-     * @param string            $end 结束标签
-     * @param integer|string    $dec 小数位
-     * @return mixed
+     * @access public
+     * @param  string  $start 开始标签
+     * @param  string  $end   结束标签
+     * @param  integer $dec   小数位
+     * @return string
      */
      */
     public static function getMemPeak($start, $end, $dec = 2)
     public static function getMemPeak($start, $end, $dec = 2)
     {
     {
         if (!isset(self::$mem['peak'][$end])) {
         if (!isset(self::$mem['peak'][$end])) {
             self::$mem['peak'][$end] = memory_get_peak_usage();
             self::$mem['peak'][$end] = memory_get_peak_usage();
         }
         }
+
         $size = self::$mem['peak'][$end] - self::$mem['peak'][$start];
         $size = self::$mem['peak'][$end] - self::$mem['peak'][$start];
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $a    = ['B', 'KB', 'MB', 'GB', 'TB'];
         $pos  = 0;
         $pos  = 0;
+
         while ($size >= 1024) {
         while ($size >= 1024) {
             $size /= 1024;
             $size /= 1024;
             $pos++;
             $pos++;
         }
         }
+
         return round($size, $dec) . " " . $a[$pos];
         return round($size, $dec) . " " . $a[$pos];
     }
     }
 
 
     /**
     /**
      * 获取文件加载信息
      * 获取文件加载信息
-     * @param bool  $detail 是否显示详细
+     * @access public
+     * @param  bool $detail 是否显示详细
      * @return integer|array
      * @return integer|array
      */
      */
     public static function getFile($detail = false)
     public static function getFile($detail = false)
     {
     {
+        $files = get_included_files();
+
         if ($detail) {
         if ($detail) {
-            $files = get_included_files();
-            $info  = [];
-            foreach ($files as $key => $file) {
+            $info = [];
+
+            foreach ($files as $file) {
                 $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
                 $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';
             }
             }
+
             return $info;
             return $info;
         }
         }
-        return count(get_included_files());
+
+        return count($files);
     }
     }
 
 
     /**
     /**
      * 浏览器友好的变量输出
      * 浏览器友好的变量输出
-     * @param mixed         $var 变量
-     * @param boolean       $echo 是否输出 默认为true 如果为false 则返回输出字符串
-     * @param string        $label 标签 默认为空
-     * @param integer       $flags htmlspecialchars flags
-     * @return void|string
+     * @access public
+     * @param  mixed       $var   变量
+     * @param  boolean     $echo  是否输出(默认为 true,为 false 则返回输出字符串)
+     * @param  string|null $label 标签(默认为空)
+     * @param  integer     $flags htmlspecialchars 的标志
+     * @return null|string
      */
      */
     public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
     public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
     {
     {
         $label = (null === $label) ? '' : rtrim($label) . ':';
         $label = (null === $label) ? '' : rtrim($label) . ':';
+
         ob_start();
         ob_start();
         var_dump($var);
         var_dump($var);
-        $output = ob_get_clean();
-        $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
+        $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', ob_get_clean());
+
         if (IS_CLI) {
         if (IS_CLI) {
             $output = PHP_EOL . $label . $output . PHP_EOL;
             $output = PHP_EOL . $label . $output . PHP_EOL;
         } else {
         } else {
             if (!extension_loaded('xdebug')) {
             if (!extension_loaded('xdebug')) {
                 $output = htmlspecialchars($output, $flags);
                 $output = htmlspecialchars($output, $flags);
             }
             }
+
             $output = '<pre>' . $label . $output . '</pre>';
             $output = '<pre>' . $label . $output . '</pre>';
         }
         }
+
         if ($echo) {
         if ($echo) {
             echo($output);
             echo($output);
             return;
             return;
-        } else {
-            return $output;
         }
         }
+
+        return $output;
     }
     }
 
 
+    /**
+     * 调试信息注入到响应中
+     * @access public
+     * @param  Response $response 响应实例
+     * @param  string   $content  返回的字符串
+     * @return void
+     */
     public static function inject(Response $response, &$content)
     public static function inject(Response $response, &$content)
     {
     {
-        $config  = Config::get('trace');
-        $type    = isset($config['type']) ? $config['type'] : 'Html';
-        $request = Request::instance();
-        $class   = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
+        $config = Config::get('trace');
+        $type   = isset($config['type']) ? $config['type'] : 'Html';
+        $class  = false !== strpos($type, '\\') ? $type : '\\think\\debug\\' . ucwords($type);
+
         unset($config['type']);
         unset($config['type']);
-        if (class_exists($class)) {
-            $trace = new $class($config);
-        } else {
+
+        if (!class_exists($class)) {
             throw new ClassNotFoundException('class not exists:' . $class, $class);
             throw new ClassNotFoundException('class not exists:' . $class, $class);
         }
         }
 
 
+        /** @var \think\debug\Console|\think\debug\Html $trace */
+        $trace = new $class($config);
+
         if ($response instanceof Redirect) {
         if ($response instanceof Redirect) {
-            //TODO 记录
+            // TODO 记录
         } else {
         } else {
             $output = $trace->output($response, Log::getLog());
             $output = $trace->output($response, Log::getLog());
+
             if (is_string($output)) {
             if (is_string($output)) {
-                // trace调试信息注入
+                // trace 调试信息注入
                 $pos = strripos($content, '</body>');
                 $pos = strripos($content, '</body>');
                 if (false !== $pos) {
                 if (false !== $pos) {
                     $content = substr($content, 0, $pos) . $output . substr($content, $pos);
                     $content = substr($content, 0, $pos) . $output . substr($content, $pos);

+ 8 - 5
thinkphp/library/think/Env.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -15,22 +15,25 @@ class Env
 {
 {
     /**
     /**
      * 获取环境变量值
      * 获取环境变量值
-     * @param string    $name 环境变量名(支持二级 .号分割)
-     * @param string    $default  默认值
+     * @access public
+     * @param  string $name    环境变量名(支持二级 . 号分割)
+     * @param  string $default 默认值
      * @return mixed
      * @return mixed
      */
      */
     public static function get($name, $default = null)
     public static function get($name, $default = null)
     {
     {
         $result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name)));
         $result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name)));
+
         if (false !== $result) {
         if (false !== $result) {
             if ('false' === $result) {
             if ('false' === $result) {
                 $result = false;
                 $result = false;
             } elseif ('true' === $result) {
             } elseif ('true' === $result) {
                 $result = true;
                 $result = true;
             }
             }
+
             return $result;
             return $result;
-        } else {
-            return $default;
         }
         }
+
+        return $default;
     }
     }
 }
 }

+ 44 - 28
thinkphp/library/think/Error.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -20,6 +20,7 @@ class Error
 {
 {
     /**
     /**
      * 注册异常处理
      * 注册异常处理
+     * @access public
      * @return void
      * @return void
      */
      */
     public static function register()
     public static function register()
@@ -31,8 +32,10 @@ class Error
     }
     }
 
 
     /**
     /**
-     * Exception Handler
-     * @param  \Exception|\Throwable $e
+     * 异常处理
+     * @access public
+     * @param  \Exception|\Throwable $e 异常
+     * @return void
      */
      */
     public static function appException($e)
     public static function appException($e)
     {
     {
@@ -40,44 +43,50 @@ class Error
             $e = new ThrowableError($e);
             $e = new ThrowableError($e);
         }
         }
 
 
-        self::getExceptionHandler()->report($e);
+        $handler = self::getExceptionHandler();
+        $handler->report($e);
+
         if (IS_CLI) {
         if (IS_CLI) {
-            self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);
+            $handler->renderForConsole(new ConsoleOutput, $e);
         } else {
         } else {
-            self::getExceptionHandler()->render($e)->send();
+            $handler->render($e)->send();
         }
         }
     }
     }
 
 
     /**
     /**
-     * Error Handler
-     * @param  integer $errno   错误编号
-     * @param  integer $errstr  详细错误信息
-     * @param  string  $errfile 出错的文件
-     * @param  integer $errline 出错行号
-     * @param array    $errcontext
+     * 错误处理
+     * @access public
+     * @param  integer $errno      错误编号
+     * @param  integer $errstr     详细错误信息
+     * @param  string  $errfile    出错的文件
+     * @param  integer $errline    出错行号
+     * @return void
      * @throws ErrorException
      * @throws ErrorException
      */
      */
-    public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = [])
+    public static function appError($errno, $errstr, $errfile = '', $errline = 0)
     {
     {
-        $exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext);
+        $exception = new ErrorException($errno, $errstr, $errfile, $errline);
+
+        // 符合异常处理的则将错误信息托管至 think\exception\ErrorException
         if (error_reporting() & $errno) {
         if (error_reporting() & $errno) {
-            // 将错误信息托管至 think\exception\ErrorException
             throw $exception;
             throw $exception;
-        } else {
-            self::getExceptionHandler()->report($exception);
         }
         }
+
+        self::getExceptionHandler()->report($exception);
     }
     }
 
 
     /**
     /**
-     * Shutdown Handler
+     * 异常中止处理
+     * @access public
+     * @return void
      */
      */
     public static function appShutdown()
     public static function appShutdown()
     {
     {
+        // 将错误信息托管至 think\ErrorException
         if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {
         if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {
-            // 将错误信息托管至think\ErrorException
-            $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);
-
-            self::appException($exception);
+            self::appException(new ErrorException(
+                $error['type'], $error['message'], $error['file'], $error['line']
+            ));
         }
         }
 
 
         // 写入日志
         // 写入日志
@@ -86,8 +95,8 @@ class Error
 
 
     /**
     /**
      * 确定错误类型是否致命
      * 确定错误类型是否致命
-     *
-     * @param  int $type
+     * @access protected
+     * @param  int $type 错误类型
      * @return bool
      * @return bool
      */
      */
     protected static function isFatal($type)
     protected static function isFatal($type)
@@ -96,25 +105,32 @@ class Error
     }
     }
 
 
     /**
     /**
-     * Get an instance of the exception handler.
-     *
+     * 获取异常处理的实例
+     * @access public
      * @return Handle
      * @return Handle
      */
      */
     public static function getExceptionHandler()
     public static function getExceptionHandler()
     {
     {
         static $handle;
         static $handle;
+
         if (!$handle) {
         if (!$handle) {
-            // 异常处理handle
+            // 异常处理 handle
             $class = Config::get('exception_handle');
             $class = Config::get('exception_handle');
-            if ($class && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) {
+
+            if ($class && is_string($class) && class_exists($class) &&
+                is_subclass_of($class, "\\think\\exception\\Handle")
+            ) {
                 $handle = new $class;
                 $handle = new $class;
             } else {
             } else {
                 $handle = new Handle;
                 $handle = new Handle;
+
                 if ($class instanceof \Closure) {
                 if ($class instanceof \Closure) {
                     $handle->setRender($class);
                     $handle->setRender($class);
                 }
                 }
+
             }
             }
         }
         }
+
         return $handle;
         return $handle;
     }
     }
 }
 }

+ 11 - 10
thinkphp/library/think/Exception.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -13,15 +13,13 @@ namespace think;
 
 
 class Exception extends \Exception
 class Exception extends \Exception
 {
 {
-
     /**
     /**
-     * 保存异常页面显示的额外Debug数据
-     * @var array
+     * @var array 保存异常页面显示的额外 Debug 数据
      */
      */
     protected $data = [];
     protected $data = [];
 
 
     /**
     /**
-     * 设置异常额外的Debug数据
+     * 设置异常额外的 Debug 数据
      * 数据将会显示为下面的格式
      * 数据将会显示为下面的格式
      *
      *
      * Exception Data
      * Exception Data
@@ -33,8 +31,10 @@ class Exception extends \Exception
      *   key1      value1
      *   key1      value1
      *   key2      value2
      *   key2      value2
      *
      *
-     * @param string $label 数据分类,用于异常页面显示
-     * @param array  $data  需要显示的数据,必须为关联数组
+     * @access protected
+     * @param  string $label 数据分类,用于异常页面显示
+     * @param  array  $data  需要显示的数据,必须为关联数组
+     * @return void
      */
      */
     final protected function setData($label, array $data)
     final protected function setData($label, array $data)
     {
     {
@@ -42,13 +42,14 @@ class Exception extends \Exception
     }
     }
 
 
     /**
     /**
-     * 获取异常额外Debug数据
+     * 获取异常额外 Debug 数据
      * 主要用于输出到异常页面便于调试
      * 主要用于输出到异常页面便于调试
-     * @return array 由setData设置的Debug数据
+     * @access public
+     * @return array
      */
      */
     final public function getData()
     final public function getData()
     {
     {
         return $this->data;
         return $this->data;
     }
     }
-    
+
 }
 }

+ 156 - 93
thinkphp/library/think/File.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -16,25 +16,51 @@ use SplFileObject;
 class File extends SplFileObject
 class File extends SplFileObject
 {
 {
     /**
     /**
-     * 错误信息
-     * @var string
+     * @var string 错误信息
      */
      */
     private $error = '';
     private $error = '';
-    // 当前完整文件名
+
+    /**
+     * @var string 当前完整文件名
+     */
     protected $filename;
     protected $filename;
-    // 上传文件名
+
+    /**
+     * @var string 上传文件名
+     */
     protected $saveName;
     protected $saveName;
-    // 文件上传命名规则
+
+    /**
+     * @var string 文件上传命名规则
+     */
     protected $rule = 'date';
     protected $rule = 'date';
-    // 文件上传验证规则
+
+    /**
+     * @var array 文件上传验证规则
+     */
     protected $validate = [];
     protected $validate = [];
-    // 单元测试
+
+    /**
+     * @var bool 单元测试
+     */
     protected $isTest;
     protected $isTest;
-    // 上传文件信息
+
+    /**
+     * @var array 上传文件信息
+     */
     protected $info;
     protected $info;
-    // 文件hash信息
+
+    /**
+     * @var array 文件 hash 信息
+     */
     protected $hash = [];
     protected $hash = [];
 
 
+    /**
+     * File constructor.
+     * @access public
+     * @param  string $filename 文件名称
+     * @param  string $mode     访问模式
+     */
     public function __construct($filename, $mode = 'r')
     public function __construct($filename, $mode = 'r')
     {
     {
         parent::__construct($filename, $mode);
         parent::__construct($filename, $mode);
@@ -42,30 +68,35 @@ class File extends SplFileObject
     }
     }
 
 
     /**
     /**
-     * 是否测试
-     * @param  bool   $test 是否测试
+     * 设置是否是单元测试
+     * @access public
+     * @param  bool $test 是否是测试
      * @return $this
      * @return $this
      */
      */
     public function isTest($test = false)
     public function isTest($test = false)
     {
     {
         $this->isTest = $test;
         $this->isTest = $test;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 设置上传信息
      * 设置上传信息
-     * @param  array   $info 上传文件信息
+     * @access public
+     * @param  array $info 上传文件信息
      * @return $this
      * @return $this
      */
      */
     public function setUploadInfo($info)
     public function setUploadInfo($info)
     {
     {
         $this->info = $info;
         $this->info = $info;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 获取上传文件的信息
      * 获取上传文件的信息
-     * @param  string   $name
+     * @access public
+     * @param  string $name 信息名称
      * @return array|string
      * @return array|string
      */
      */
     public function getInfo($name = '')
     public function getInfo($name = '')
@@ -75,6 +106,7 @@ class File extends SplFileObject
 
 
     /**
     /**
      * 获取上传文件的文件名
      * 获取上传文件的文件名
+     * @access public
      * @return string
      * @return string
      */
      */
     public function getSaveName()
     public function getSaveName()
@@ -84,94 +116,101 @@ class File extends SplFileObject
 
 
     /**
     /**
      * 设置上传文件的保存文件名
      * 设置上传文件的保存文件名
-     * @param  string   $saveName
+     * @access public
+     * @param  string $saveName 保存名称
      * @return $this
      * @return $this
      */
      */
     public function setSaveName($saveName)
     public function setSaveName($saveName)
     {
     {
         $this->saveName = $saveName;
         $this->saveName = $saveName;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 获取文件的哈希散列值
      * 获取文件的哈希散列值
-     * @param string $type
-     * @return mixed $string
+     * @access public
+     * @param  string $type 类型
+     * @return string
      */
      */
     public function hash($type = 'sha1')
     public function hash($type = 'sha1')
     {
     {
         if (!isset($this->hash[$type])) {
         if (!isset($this->hash[$type])) {
             $this->hash[$type] = hash_file($type, $this->filename);
             $this->hash[$type] = hash_file($type, $this->filename);
         }
         }
+
         return $this->hash[$type];
         return $this->hash[$type];
     }
     }
 
 
     /**
     /**
      * 检查目录是否可写
      * 检查目录是否可写
-     * @param  string   $path    目录
+     * @access protected
+     * @param  string $path 目录
      * @return boolean
      * @return boolean
      */
      */
     protected function checkPath($path)
     protected function checkPath($path)
     {
     {
-        if (is_dir($path)) {
+        if (is_dir($path) || mkdir($path, 0755, true)) {
             return true;
             return true;
         }
         }
 
 
-        if (mkdir($path, 0755, true)) {
-            return true;
-        } else {
-            $this->error = "目录 {$path} 创建失败!";
-            return false;
-        }
+        $this->error = ['directory {:path} creation failed', ['path' => $path]];
+
+        return false;
     }
     }
 
 
     /**
     /**
      * 获取文件类型信息
      * 获取文件类型信息
+     * @access public
      * @return string
      * @return string
      */
      */
     public function getMime()
     public function getMime()
     {
     {
         $finfo = finfo_open(FILEINFO_MIME_TYPE);
         $finfo = finfo_open(FILEINFO_MIME_TYPE);
+
         return finfo_file($finfo, $this->filename);
         return finfo_file($finfo, $this->filename);
     }
     }
 
 
     /**
     /**
      * 设置文件的命名规则
      * 设置文件的命名规则
-     * @param  string   $rule    文件命名规则
+     * @access public
+     * @param  string $rule 文件命名规则
      * @return $this
      * @return $this
      */
      */
     public function rule($rule)
     public function rule($rule)
     {
     {
         $this->rule = $rule;
         $this->rule = $rule;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 设置上传文件的验证规则
      * 设置上传文件的验证规则
-     * @param  array   $rule    验证规则
+     * @access public
+     * @param  array $rule 验证规则
      * @return $this
      * @return $this
      */
      */
-    public function validate($rule = [])
+    public function validate(array $rule = [])
     {
     {
         $this->validate = $rule;
         $this->validate = $rule;
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * 检测是否合法的上传文件
      * 检测是否合法的上传文件
+     * @access public
      * @return bool
      * @return bool
      */
      */
     public function isValid()
     public function isValid()
     {
     {
-        if ($this->isTest) {
-            return is_file($this->filename);
-        }
-        return is_uploaded_file($this->filename);
+        return $this->isTest ? is_file($this->filename) : is_uploaded_file($this->filename);
     }
     }
 
 
     /**
     /**
      * 检测上传文件
      * 检测上传文件
-     * @param  array   $rule    验证规则
+     * @access public
+     * @param  array $rule 验证规则
      * @return bool
      * @return bool
      */
      */
     public function check($rule = [])
     public function check($rule = [])
@@ -180,25 +219,25 @@ class File extends SplFileObject
 
 
         /* 检查文件大小 */
         /* 检查文件大小 */
         if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
         if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
-            $this->error = '上传文件大小不符!';
+            $this->error = 'filesize not match';
             return false;
             return false;
         }
         }
 
 
-        /* 检查文件Mime类型 */
+        /* 检查文件 Mime 类型 */
         if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
         if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
-            $this->error = '上传文件MIME类型不允许!';
+            $this->error = 'mimetype to upload is not allowed';
             return false;
             return false;
         }
         }
 
 
         /* 检查文件后缀 */
         /* 检查文件后缀 */
         if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
         if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
-            $this->error = '上传文件后缀不允许';
+            $this->error = 'extensions to upload is not allowed';
             return false;
             return false;
         }
         }
 
 
         /* 检查图像文件 */
         /* 检查图像文件 */
         if (!$this->checkImg()) {
         if (!$this->checkImg()) {
-            $this->error = '非法图像文件!';
+            $this->error = 'illegal image files';
             return false;
             return false;
         }
         }
 
 
@@ -207,7 +246,8 @@ class File extends SplFileObject
 
 
     /**
     /**
      * 检测上传文件后缀
      * 检测上传文件后缀
-     * @param  array|string   $ext    允许后缀
+     * @access public
+     * @param  array|string $ext 允许后缀
      * @return bool
      * @return bool
      */
      */
     public function checkExt($ext)
     public function checkExt($ext)
@@ -215,77 +255,76 @@ class File extends SplFileObject
         if (is_string($ext)) {
         if (is_string($ext)) {
             $ext = explode(',', $ext);
             $ext = explode(',', $ext);
         }
         }
+
         $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
         $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
-        if (!in_array($extension, $ext)) {
-            return false;
-        }
-        return true;
+
+        return in_array($extension, $ext);
     }
     }
 
 
     /**
     /**
      * 检测图像文件
      * 检测图像文件
+     * @access public
      * @return bool
      * @return bool
      */
      */
     public function checkImg()
     public function checkImg()
     {
     {
         $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
         $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
-        /* 对图像文件进行严格检测 */
-        if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13])) {
-            return false;
-        }
-        return true;
+
+        // 如果上传的不是图片,或者是图片而且后缀确实符合图片类型则返回 true
+        return !in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) || in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13]);
     }
     }
 
 
-    // 判断图像类型
+    /**
+     * 判断图像类型
+     * @access protected
+     * @param  string $image 图片名称
+     * @return bool|int
+     */
     protected function getImageType($image)
     protected function getImageType($image)
     {
     {
         if (function_exists('exif_imagetype')) {
         if (function_exists('exif_imagetype')) {
             return exif_imagetype($image);
             return exif_imagetype($image);
-        } else {
-            try {
-                $info = getimagesize($image);
-                return $info ? $info[2] : false;
-            } catch (\Exception $e) {
-                return false;
-            }
+        }
+
+        try {
+            $info = getimagesize($image);
+            return $info ? $info[2] : false;
+        } catch (\Exception $e) {
+            return false;
         }
         }
     }
     }
 
 
     /**
     /**
      * 检测上传文件大小
      * 检测上传文件大小
-     * @param  integer   $size    最大大小
+     * @access public
+     * @param  integer $size 最大大小
      * @return bool
      * @return bool
      */
      */
     public function checkSize($size)
     public function checkSize($size)
     {
     {
-        if ($this->getSize() > $size) {
-            return false;
-        }
-        return true;
+        return $this->getSize() <= $size;
     }
     }
 
 
     /**
     /**
      * 检测上传文件类型
      * 检测上传文件类型
-     * @param  array|string   $mime    允许类型
+     * @access public
+     * @param  array|string $mime 允许类型
      * @return bool
      * @return bool
      */
      */
     public function checkMime($mime)
     public function checkMime($mime)
     {
     {
-        if (is_string($mime)) {
-            $mime = explode(',', $mime);
-        }
-        if (!in_array(strtolower($this->getMime()), $mime)) {
-            return false;
-        }
-        return true;
+        $mime = is_string($mime) ? explode(',', $mime) : $mime;
+
+        return in_array(strtolower($this->getMime()), $mime);
     }
     }
 
 
     /**
     /**
      * 移动文件
      * 移动文件
-     * @param  string           $path    保存路径
-     * @param  string|bool      $savename    保存的文件名 默认自动生成
-     * @param  boolean          $replace 同名文件是否覆盖
-     * @return false|File false-失败 否则返回File实例
+     * @access public
+     * @param  string      $path     保存路径
+     * @param  string|bool $savename 保存的文件名 默认自动生成
+     * @param  boolean     $replace  同名文件是否覆盖
+     * @return false|File
      */
      */
     public function move($path, $savename = true, $replace = true)
     public function move($path, $savename = true, $replace = true)
     {
     {
@@ -297,7 +336,7 @@ class File extends SplFileObject
 
 
         // 检测合法性
         // 检测合法性
         if (!$this->isValid()) {
         if (!$this->isValid()) {
-            $this->error = '非法上传文件';
+            $this->error = 'upload illegal files';
             return false;
             return false;
         }
         }
 
 
@@ -305,6 +344,7 @@ class File extends SplFileObject
         if (!$this->check()) {
         if (!$this->check()) {
             return false;
             return false;
         }
         }
+
         $path = rtrim($path, DS) . DS;
         $path = rtrim($path, DS) . DS;
         // 文件保存命名规则
         // 文件保存命名规则
         $saveName = $this->buildSaveName($savename);
         $saveName = $this->buildSaveName($savename);
@@ -315,9 +355,9 @@ class File extends SplFileObject
             return false;
             return false;
         }
         }
 
 
-        /* 不覆盖同名文件 */
+        // 不覆盖同名文件
         if (!$replace && is_file($filename)) {
         if (!$replace && is_file($filename)) {
-            $this->error = '存在同名文件' . $filename;
+            $this->error = ['has the same filename: {:filename}', ['filename' => $filename]];
             return false;
             return false;
         }
         }
 
 
@@ -325,25 +365,27 @@ class File extends SplFileObject
         if ($this->isTest) {
         if ($this->isTest) {
             rename($this->filename, $filename);
             rename($this->filename, $filename);
         } elseif (!move_uploaded_file($this->filename, $filename)) {
         } elseif (!move_uploaded_file($this->filename, $filename)) {
-            $this->error = '文件上传保存错误!';
+            $this->error = 'upload write error';
             return false;
             return false;
         }
         }
-        // 返回 File对象实例
+
+        // 返回 File 对象实例
         $file = new self($filename);
         $file = new self($filename);
-        $file->setSaveName($saveName);
-        $file->setUploadInfo($this->info);
+        $file->setSaveName($saveName)->setUploadInfo($this->info);
+
         return $file;
         return $file;
     }
     }
 
 
     /**
     /**
      * 获取保存文件名
      * 获取保存文件名
-     * @param  string|bool   $savename    保存的文件名 默认自动生成
+     * @access protected
+     * @param  string|bool $savename 保存的文件名 默认自动生成
      * @return string
      * @return string
      */
      */
     protected function buildSaveName($savename)
     protected function buildSaveName($savename)
     {
     {
+        // 自动生成文件名
         if (true === $savename) {
         if (true === $savename) {
-            // 自动生成文件名
             if ($this->rule instanceof \Closure) {
             if ($this->rule instanceof \Closure) {
                 $savename = call_user_func_array($this->rule, [$this]);
                 $savename = call_user_func_array($this->rule, [$this]);
             } else {
             } else {
@@ -362,52 +404,73 @@ class File extends SplFileObject
                         }
                         }
                 }
                 }
             }
             }
-        } elseif ('' === $savename) {
+        } elseif ('' === $savename || false === $savename) {
             $savename = $this->getInfo('name');
             $savename = $this->getInfo('name');
         }
         }
+
         if (!strpos($savename, '.')) {
         if (!strpos($savename, '.')) {
             $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
             $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
         }
         }
+
         return $savename;
         return $savename;
     }
     }
 
 
     /**
     /**
      * 获取错误代码信息
      * 获取错误代码信息
-     * @param int $errorNo  错误号
+     * @access private
+     * @param  int $errorNo 错误号
+     * @return $this
      */
      */
     private function error($errorNo)
     private function error($errorNo)
     {
     {
         switch ($errorNo) {
         switch ($errorNo) {
             case 1:
             case 1:
             case 2:
             case 2:
-                $this->error = '上传文件大小超过了最大值!';
+                $this->error = 'upload File size exceeds the maximum value';
                 break;
                 break;
             case 3:
             case 3:
-                $this->error = '文件只有部分被上传!';
+                $this->error = 'only the portion of file is uploaded';
                 break;
                 break;
             case 4:
             case 4:
-                $this->error = '没有文件被上传!';
+                $this->error = 'no file to uploaded';
                 break;
                 break;
             case 6:
             case 6:
-                $this->error = '找不到临时文件夹!';
+                $this->error = 'upload temp dir not found';
                 break;
                 break;
             case 7:
             case 7:
-                $this->error = '文件写入失败!';
+                $this->error = 'file write error';
                 break;
                 break;
             default:
             default:
-                $this->error = '未知上传错误!';
+                $this->error = 'unknown upload error';
         }
         }
+
+        return $this;
     }
     }
 
 
     /**
     /**
-     * 获取错误信息
-     * @return mixed
+     * 获取错误信息(支持多语言)
+     * @access public
+     * @return string
      */
      */
     public function getError()
     public function getError()
     {
     {
-        return $this->error;
+        if (is_array($this->error)) {
+            list($msg, $vars) = $this->error;
+        } else {
+            $msg  = $this->error;
+            $vars = [];
+        }
+
+        return Lang::has($msg) ? Lang::get($msg, $vars) : $msg;
     }
     }
 
 
+    /**
+     * 魔法方法,获取文件的 hash 值
+     * @access public
+     * @param  string $method 方法名
+     * @param  mixed  $args   调用参数
+     * @return string
+     */
     public function __call($method, $args)
     public function __call($method, $args)
     {
     {
         return $this->hash($method);
         return $this->hash($method);

+ 37 - 25
thinkphp/library/think/Hook.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -13,19 +13,23 @@ namespace think;
 
 
 class Hook
 class Hook
 {
 {
-
+    /**
+     * @var array 标签
+     */
     private static $tags = [];
     private static $tags = [];
 
 
     /**
     /**
      * 动态添加行为扩展到某个标签
      * 动态添加行为扩展到某个标签
-     * @param string    $tag 标签名称
-     * @param mixed     $behavior 行为名称
-     * @param bool      $first 是否放到开头执行
+     * @access public
+     * @param  string $tag      标签名称
+     * @param  mixed  $behavior 行为名称
+     * @param  bool   $first    是否放到开头执行
      * @return void
      * @return void
      */
      */
     public static function add($tag, $behavior, $first = false)
     public static function add($tag, $behavior, $first = false)
     {
     {
         isset(self::$tags[$tag]) || self::$tags[$tag] = [];
         isset(self::$tags[$tag]) || self::$tags[$tag] = [];
+
         if (is_array($behavior) && !is_callable($behavior)) {
         if (is_array($behavior) && !is_callable($behavior)) {
             if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
             if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {
                 unset($behavior['_overlay']);
                 unset($behavior['_overlay']);
@@ -43,8 +47,10 @@ class Hook
 
 
     /**
     /**
      * 批量导入插件
      * 批量导入插件
-     * @param array        $tags 插件信息
-     * @param boolean     $recursive 是否递归合并
+     * @access public
+     * @param  array   $tags      插件信息
+     * @param  boolean $recursive 是否递归合并
+     * @return void
      */
      */
     public static function import(array $tags, $recursive = true)
     public static function import(array $tags, $recursive = true)
     {
     {
@@ -59,55 +65,59 @@ class Hook
 
 
     /**
     /**
      * 获取插件信息
      * 获取插件信息
-     * @param string $tag 插件位置 留空获取全部
+     * @access public
+     * @param  string $tag 插件位置(留空获取全部)
      * @return array
      * @return array
      */
      */
     public static function get($tag = '')
     public static function get($tag = '')
     {
     {
         if (empty($tag)) {
         if (empty($tag)) {
-            //获取全部的插件信息
             return self::$tags;
             return self::$tags;
-        } else {
-            return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
         }
         }
+
+        return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];
     }
     }
 
 
     /**
     /**
      * 监听标签的行为
      * 监听标签的行为
-     * @param string $tag    标签名称
-     * @param mixed  $params 传入参数
-     * @param mixed  $extra  额外参数
-     * @param bool   $once   只获取一个有效返回值
+     * @access public
+     * @param  string $tag    标签名称
+     * @param  mixed  $params 传入参数
+     * @param  mixed  $extra  额外参数
+     * @param  bool   $once   只获取一个有效返回值
      * @return mixed
      * @return mixed
      */
      */
     public static function listen($tag, &$params = null, $extra = null, $once = false)
     public static function listen($tag, &$params = null, $extra = null, $once = false)
     {
     {
         $results = [];
         $results = [];
-        $tags    = static::get($tag);
-        foreach ($tags as $key => $name) {
+
+        foreach (static::get($tag) as $key => $name) {
             $results[$key] = self::exec($name, $tag, $params, $extra);
             $results[$key] = self::exec($name, $tag, $params, $extra);
-            if (false === $results[$key]) {
-                // 如果返回false 则中断行为执行
-                break;
-            } elseif (!is_null($results[$key]) && $once) {
+
+            // 如果返回 false,或者仅获取一个有效返回则中断行为执行
+            if (false === $results[$key] || (!is_null($results[$key]) && $once)) {
                 break;
                 break;
             }
             }
         }
         }
+
         return $once ? end($results) : $results;
         return $once ? end($results) : $results;
     }
     }
 
 
     /**
     /**
      * 执行某个行为
      * 执行某个行为
-     * @param mixed     $class 要执行的行为
-     * @param string    $tag 方法名(标签名)
-     * @param Mixed     $params 传人的参数
-     * @param mixed     $extra 额外参数
+     * @access public
+     * @param  mixed  $class  要执行的行为
+     * @param  string $tag    方法名(标签名)
+     * @param  mixed  $params 传人的参数
+     * @param  mixed  $extra  额外参数
      * @return mixed
      * @return mixed
      */
      */
     public static function exec($class, $tag = '', &$params = null, $extra = null)
     public static function exec($class, $tag = '', &$params = null, $extra = null)
     {
     {
         App::$debug && Debug::remark('behavior_start', 'time');
         App::$debug && Debug::remark('behavior_start', 'time');
+
         $method = Loader::parseName($tag, 1, false);
         $method = Loader::parseName($tag, 1, false);
+
         if ($class instanceof \Closure) {
         if ($class instanceof \Closure) {
             $result = call_user_func_array($class, [ & $params, $extra]);
             $result = call_user_func_array($class, [ & $params, $extra]);
             $class  = 'Closure';
             $class  = 'Closure';
@@ -126,10 +136,12 @@ class Hook
             $method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
             $method = ($tag && is_callable([$obj, $method])) ? $method : 'run';
             $result = $obj->$method($params, $extra);
             $result = $obj->$method($params, $extra);
         }
         }
+
         if (App::$debug) {
         if (App::$debug) {
             Debug::remark('behavior_end', 'time');
             Debug::remark('behavior_end', 'time');
             Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
             Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');
         }
         }
+
         return $result;
         return $result;
     }
     }
 
 

+ 84 - 42
thinkphp/library/think/Lang.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -13,114 +13,148 @@ namespace think;
 
 
 class Lang
 class Lang
 {
 {
-    // 语言数据
+    /**
+     * @var array 语言数据
+     */
     private static $lang = [];
     private static $lang = [];
-    // 语言作用域
+
+    /**
+     * @var string 语言作用域
+     */
     private static $range = 'zh-cn';
     private static $range = 'zh-cn';
-    // 语言自动侦测的变量
+
+    /**
+     * @var string 语言自动侦测的变量
+     */
     protected static $langDetectVar = 'lang';
     protected static $langDetectVar = 'lang';
-    // 语言Cookie变量
+
+    /**
+     * @var string 语言 Cookie 变量
+     */
     protected static $langCookieVar = 'think_var';
     protected static $langCookieVar = 'think_var';
-    // 语言Cookie的过期时间
+
+    /**
+     * @var int 语言 Cookie 的过期时间
+     */
     protected static $langCookieExpire = 3600;
     protected static $langCookieExpire = 3600;
-    // 允许语言列表
+
+    /**
+     * @var array 允许语言列表
+     */
     protected static $allowLangList = [];
     protected static $allowLangList = [];
-    // Accept-Language转义为对应语言包名称 系统默认配置
-    protected static $acceptLanguage = [
-        'zh-hans-cn' => 'zh-cn',
-    ];
 
 
-    // 设定当前的语言
+    /**
+     * @var array Accept-Language 转义为对应语言包名称 系统默认配置
+     */
+    protected static $acceptLanguage = ['zh-hans-cn' => 'zh-cn'];
+
+    /**
+     * 设定当前的语言
+     * @access public
+     * @param  string $range 语言作用域
+     * @return string
+     */
     public static function range($range = '')
     public static function range($range = '')
     {
     {
-        if ('' == $range) {
-            return self::$range;
-        } else {
+        if ($range) {
             self::$range = $range;
             self::$range = $range;
         }
         }
+
         return self::$range;
         return self::$range;
     }
     }
 
 
     /**
     /**
      * 设置语言定义(不区分大小写)
      * 设置语言定义(不区分大小写)
-     * @param string|array  $name 语言变量
-     * @param string        $value 语言值
-     * @param string        $range 语言作用域
+     * @access public
+     * @param  string|array  $name  语言变量
+     * @param  string        $value 语言值
+     * @param  string        $range 语言作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function set($name, $value = null, $range = '')
     public static function set($name, $value = null, $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
-        // 批量定义
+
         if (!isset(self::$lang[$range])) {
         if (!isset(self::$lang[$range])) {
             self::$lang[$range] = [];
             self::$lang[$range] = [];
         }
         }
+
         if (is_array($name)) {
         if (is_array($name)) {
             return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range];
             return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range];
-        } else {
-            return self::$lang[$range][strtolower($name)] = $value;
         }
         }
+
+        return self::$lang[$range][strtolower($name)] = $value;
     }
     }
 
 
     /**
     /**
      * 加载语言定义(不区分大小写)
      * 加载语言定义(不区分大小写)
-     * @param array|string $file 语言文件
-     * @param string $range 语言作用域
+     * @access public
+     * @param  array|string $file 语言文件
+     * @param  string $range      语言作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function load($file, $range = '')
     public static function load($file, $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
+        $file  = is_string($file) ? [$file] : $file;
+
         if (!isset(self::$lang[$range])) {
         if (!isset(self::$lang[$range])) {
             self::$lang[$range] = [];
             self::$lang[$range] = [];
         }
         }
-        // 批量定义
-        if (is_string($file)) {
-            $file = [$file];
-        }
+
         $lang = [];
         $lang = [];
+
         foreach ($file as $_file) {
         foreach ($file as $_file) {
             if (is_file($_file)) {
             if (is_file($_file)) {
                 // 记录加载信息
                 // 记录加载信息
                 App::$debug && Log::record('[ LANG ] ' . $_file, 'info');
                 App::$debug && Log::record('[ LANG ] ' . $_file, 'info');
+
                 $_lang = include $_file;
                 $_lang = include $_file;
+
                 if (is_array($_lang)) {
                 if (is_array($_lang)) {
                     $lang = array_change_key_case($_lang) + $lang;
                     $lang = array_change_key_case($_lang) + $lang;
                 }
                 }
             }
             }
         }
         }
+
         if (!empty($lang)) {
         if (!empty($lang)) {
             self::$lang[$range] = $lang + self::$lang[$range];
             self::$lang[$range] = $lang + self::$lang[$range];
         }
         }
+
         return self::$lang[$range];
         return self::$lang[$range];
     }
     }
 
 
     /**
     /**
      * 获取语言定义(不区分大小写)
      * 获取语言定义(不区分大小写)
-     * @param string|null   $name 语言变量
-     * @param string        $range 语言作用域
+     * @access public
+     * @param  string|null $name  语言变量
+     * @param  string      $range 语言作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function has($name, $range = '')
     public static function has($name, $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
+
         return isset(self::$lang[$range][strtolower($name)]);
         return isset(self::$lang[$range][strtolower($name)]);
     }
     }
 
 
     /**
     /**
      * 获取语言定义(不区分大小写)
      * 获取语言定义(不区分大小写)
-     * @param string|null   $name 语言变量
-     * @param array         $vars 变量替换
-     * @param string        $range 语言作用域
+     * @access public
+     * @param  string|null $name  语言变量
+     * @param  array       $vars  变量替换
+     * @param  string      $range 语言作用域
      * @return mixed
      * @return mixed
      */
      */
     public static function get($name = null, $vars = [], $range = '')
     public static function get($name = null, $vars = [], $range = '')
     {
     {
         $range = $range ?: self::$range;
         $range = $range ?: self::$range;
+
         // 空参数返回所有定义
         // 空参数返回所有定义
         if (empty($name)) {
         if (empty($name)) {
             return self::$lang[$range];
             return self::$lang[$range];
         }
         }
+
         $key   = strtolower($name);
         $key   = strtolower($name);
         $value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name;
         $value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name;
 
 
@@ -145,45 +179,50 @@ class Lang
             }
             }
 
 
         }
         }
+
         return $value;
         return $value;
     }
     }
 
 
     /**
     /**
      * 自动侦测设置获取语言选择
      * 自动侦测设置获取语言选择
+     * @access public
      * @return string
      * @return string
      */
      */
     public static function detect()
     public static function detect()
     {
     {
-        // 自动侦测设置获取语言选择
         $langSet = '';
         $langSet = '';
 
 
         if (isset($_GET[self::$langDetectVar])) {
         if (isset($_GET[self::$langDetectVar])) {
-            // url中设置了语言变量
+            // url 中设置了语言变量
             $langSet = strtolower($_GET[self::$langDetectVar]);
             $langSet = strtolower($_GET[self::$langDetectVar]);
         } elseif (isset($_COOKIE[self::$langCookieVar])) {
         } elseif (isset($_COOKIE[self::$langCookieVar])) {
-            // Cookie中设置了语言变量
+            // Cookie 中设置了语言变量
             $langSet = strtolower($_COOKIE[self::$langCookieVar]);
             $langSet = strtolower($_COOKIE[self::$langCookieVar]);
         } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
         } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
             // 自动侦测浏览器语言
             // 自动侦测浏览器语言
             preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
             preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
             $langSet     = strtolower($matches[1]);
             $langSet     = strtolower($matches[1]);
             $acceptLangs = Config::get('header_accept_lang');
             $acceptLangs = Config::get('header_accept_lang');
+
             if (isset($acceptLangs[$langSet])) {
             if (isset($acceptLangs[$langSet])) {
                 $langSet = $acceptLangs[$langSet];
                 $langSet = $acceptLangs[$langSet];
             } elseif (isset(self::$acceptLanguage[$langSet])) {
             } elseif (isset(self::$acceptLanguage[$langSet])) {
                 $langSet = self::$acceptLanguage[$langSet];
                 $langSet = self::$acceptLanguage[$langSet];
             }
             }
         }
         }
+
+        // 合法的语言
         if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
         if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {
-            // 合法的语言
             self::$range = $langSet ?: self::$range;
             self::$range = $langSet ?: self::$range;
         }
         }
+
         return self::$range;
         return self::$range;
     }
     }
 
 
     /**
     /**
      * 设置语言自动侦测的变量
      * 设置语言自动侦测的变量
-     * @param string $var 变量名称
+     * @access public
+     * @param  string $var 变量名称
      * @return void
      * @return void
      */
      */
     public static function setLangDetectVar($var)
     public static function setLangDetectVar($var)
@@ -192,8 +231,9 @@ class Lang
     }
     }
 
 
     /**
     /**
-     * 设置语言的cookie保存变量
-     * @param string $var 变量名称
+     * 设置语言的 cookie 保存变量
+     * @access public
+     * @param  string $var 变量名称
      * @return void
      * @return void
      */
      */
     public static function setLangCookieVar($var)
     public static function setLangCookieVar($var)
@@ -202,8 +242,9 @@ class Lang
     }
     }
 
 
     /**
     /**
-     * 设置语言的cookie的过期时间
-     * @param string $expire 过期时间
+     * 设置语言的 cookie 的过期时间
+     * @access public
+     * @param  string $expire 过期时间
      * @return void
      * @return void
      */
      */
     public static function setLangCookieExpire($expire)
     public static function setLangCookieExpire($expire)
@@ -213,7 +254,8 @@ class Lang
 
 
     /**
     /**
      * 设置允许的语言列表
      * 设置允许的语言列表
-     * @param array $list 语言列表
+     * @access public
+     * @param  array $list 语言列表
      * @return void
      * @return void
      */
      */
     public static function setAllowLangList($list)
     public static function setAllowLangList($list)

+ 302 - 195
thinkphp/library/think/Loader.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -15,26 +15,57 @@ use think\exception\ClassNotFoundException;
 
 
 class Loader
 class Loader
 {
 {
+    /**
+     * @var array 实例数组
+     */
     protected static $instance = [];
     protected static $instance = [];
-    // 类名映射
-    protected static $map = [];
 
 
-    // 命名空间别名
+    /**
+     * @var array 类名映射
+     */
+    protected static $classMap = [];
+
+    /**
+     * @var array 命名空间别名
+     */
     protected static $namespaceAlias = [];
     protected static $namespaceAlias = [];
 
 
-    // PSR-4
+    /**
+     * @var array PSR-4 命名空间前缀长度映射
+     */
     private static $prefixLengthsPsr4 = [];
     private static $prefixLengthsPsr4 = [];
-    private static $prefixDirsPsr4    = [];
-    private static $fallbackDirsPsr4  = [];
 
 
-    // PSR-0
-    private static $prefixesPsr0     = [];
+    /**
+     * @var array PSR-4 的加载目录
+     */
+    private static $prefixDirsPsr4 = [];
+
+    /**
+     * @var array PSR-4 加载失败的回退目录
+     */
+    private static $fallbackDirsPsr4 = [];
+
+    /**
+     * @var array PSR-0 命名空间前缀映射
+     */
+    private static $prefixesPsr0 = [];
+
+    /**
+     * @var array PSR-0 加载失败的回退目录
+     */
     private static $fallbackDirsPsr0 = [];
     private static $fallbackDirsPsr0 = [];
 
 
-    // 自动加载的文件
-    private static $autoloadFiles = [];
+    /**
+     * @var array 需要加载的文件
+     */
+    private static $files = [];
 
 
-    // 自动加载
+    /**
+     * 自动加载
+     * @access public
+     * @param  string $class 类名
+     * @return bool
+     */
     public static function autoload($class)
     public static function autoload($class)
     {
     {
         // 检测命名空间别名
         // 检测命名空间别名
@@ -49,33 +80,33 @@ class Loader
         }
         }
 
 
         if ($file = self::findFile($class)) {
         if ($file = self::findFile($class)) {
-
-            // Win环境严格区分大小写
-            if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
-                return false;
+            // 非 Win 环境不严格区分大小写
+            if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) {
+                __include_file($file);
+                return true;
             }
             }
-
-            __include_file($file);
-            return true;
         }
         }
+
+        return false;
     }
     }
 
 
     /**
     /**
      * 查找文件
      * 查找文件
-     * @param $class
-     * @return bool
+     * @access private
+     * @param  string $class 类名
+     * @return bool|string
      */
      */
     private static function findFile($class)
     private static function findFile($class)
     {
     {
-        if (!empty(self::$map[$class])) {
-            // 类库映射
-            return self::$map[$class];
+        // 类库映射
+        if (!empty(self::$classMap[$class])) {
+            return self::$classMap[$class];
         }
         }
 
 
         // 查找 PSR-4
         // 查找 PSR-4
         $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
         $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
+        $first           = $class[0];
 
 
-        $first = $class[0];
         if (isset(self::$prefixLengthsPsr4[$first])) {
         if (isset(self::$prefixLengthsPsr4[$first])) {
             foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
             foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
                 if (0 === strpos($class, $prefix)) {
                 if (0 === strpos($class, $prefix)) {
@@ -97,7 +128,7 @@ class Loader
 
 
         // 查找 PSR-0
         // 查找 PSR-0
         if (false !== $pos = strrpos($class, '\\')) {
         if (false !== $pos = strrpos($class, '\\')) {
-            // namespaced class name
+            // namespace class name
             $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
             $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
             . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
             . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
         } else {
         } else {
@@ -124,20 +155,33 @@ class Loader
             }
             }
         }
         }
 
 
-        return self::$map[$class] = false;
+        // 找不到则设置映射为 false 并返回
+        return self::$classMap[$class] = false;
     }
     }
 
 
-    // 注册classmap
+    /**
+     * 注册 classmap
+     * @access public
+     * @param  string|array $class 类名
+     * @param  string       $map   映射
+     * @return void
+     */
     public static function addClassMap($class, $map = '')
     public static function addClassMap($class, $map = '')
     {
     {
         if (is_array($class)) {
         if (is_array($class)) {
-            self::$map = array_merge(self::$map, $class);
+            self::$classMap = array_merge(self::$classMap, $class);
         } else {
         } else {
-            self::$map[$class] = $map;
+            self::$classMap[$class] = $map;
         }
         }
     }
     }
 
 
-    // 注册命名空间
+    /**
+     * 注册命名空间
+     * @access public
+     * @param  string|array $namespace 命名空间
+     * @param  string       $path      路径
+     * @return void
+     */
     public static function addNamespace($namespace, $path = '')
     public static function addNamespace($namespace, $path = '')
     {
     {
         if (is_array($namespace)) {
         if (is_array($namespace)) {
@@ -149,84 +193,77 @@ class Loader
         }
         }
     }
     }
 
 
-    // 添加Ps0空间
+    /**
+     * 添加 PSR-0 命名空间
+     * @access private
+     * @param  array|string $prefix  空间前缀
+     * @param  array        $paths   路径
+     * @param  bool         $prepend 预先设置的优先级更高
+     * @return void
+     */
     private static function addPsr0($prefix, $paths, $prepend = false)
     private static function addPsr0($prefix, $paths, $prepend = false)
     {
     {
         if (!$prefix) {
         if (!$prefix) {
-            if ($prepend) {
-                self::$fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
-                    self::$fallbackDirsPsr0
-                );
+            self::$fallbackDirsPsr0 = $prepend ?
+            array_merge((array) $paths, self::$fallbackDirsPsr0) :
+            array_merge(self::$fallbackDirsPsr0, (array) $paths);
+        } else {
+            $first = $prefix[0];
+
+            if (!isset(self::$prefixesPsr0[$first][$prefix])) {
+                self::$prefixesPsr0[$first][$prefix] = (array) $paths;
             } else {
             } else {
-                self::$fallbackDirsPsr0 = array_merge(
-                    self::$fallbackDirsPsr0,
-                    (array) $paths
-                );
+                self::$prefixesPsr0[$first][$prefix] = $prepend ?
+                array_merge((array) $paths, self::$prefixesPsr0[$first][$prefix]) :
+                array_merge(self::$prefixesPsr0[$first][$prefix], (array) $paths);
             }
             }
-
-            return;
-        }
-
-        $first = $prefix[0];
-        if (!isset(self::$prefixesPsr0[$first][$prefix])) {
-            self::$prefixesPsr0[$first][$prefix] = (array) $paths;
-
-            return;
-        }
-        if ($prepend) {
-            self::$prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
-                self::$prefixesPsr0[$first][$prefix]
-            );
-        } else {
-            self::$prefixesPsr0[$first][$prefix] = array_merge(
-                self::$prefixesPsr0[$first][$prefix],
-                (array) $paths
-            );
         }
         }
     }
     }
 
 
-    // 添加Psr4空间
+    /**
+     * 添加 PSR-4 空间
+     * @access private
+     * @param  array|string $prefix  空间前缀
+     * @param  string       $paths   路径
+     * @param  bool         $prepend 预先设置的优先级更高
+     * @return void
+     */
     private static function addPsr4($prefix, $paths, $prepend = false)
     private static function addPsr4($prefix, $paths, $prepend = false)
     {
     {
         if (!$prefix) {
         if (!$prefix) {
             // Register directories for the root namespace.
             // Register directories for the root namespace.
-            if ($prepend) {
-                self::$fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
-                    self::$fallbackDirsPsr4
-                );
-            } else {
-                self::$fallbackDirsPsr4 = array_merge(
-                    self::$fallbackDirsPsr4,
-                    (array) $paths
-                );
-            }
+            self::$fallbackDirsPsr4 = $prepend ?
+            array_merge((array) $paths, self::$fallbackDirsPsr4) :
+            array_merge(self::$fallbackDirsPsr4, (array) $paths);
+
         } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
         } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
             // Register directories for a new namespace.
             // Register directories for a new namespace.
             $length = strlen($prefix);
             $length = strlen($prefix);
             if ('\\' !== $prefix[$length - 1]) {
             if ('\\' !== $prefix[$length - 1]) {
-                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+                throw new \InvalidArgumentException(
+                    "A non-empty PSR-4 prefix must end with a namespace separator."
+                );
             }
             }
+
             self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
             self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
             self::$prefixDirsPsr4[$prefix]                = (array) $paths;
             self::$prefixDirsPsr4[$prefix]                = (array) $paths;
-        } elseif ($prepend) {
-            // Prepend directories for an already registered namespace.
-            self::$prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
-                self::$prefixDirsPsr4[$prefix]
-            );
+
         } else {
         } else {
+            self::$prefixDirsPsr4[$prefix] = $prepend ?
+            // Prepend directories for an already registered namespace.
+            array_merge((array) $paths, self::$prefixDirsPsr4[$prefix]) :
             // Append directories for an already registered namespace.
             // Append directories for an already registered namespace.
-            self::$prefixDirsPsr4[$prefix] = array_merge(
-                self::$prefixDirsPsr4[$prefix],
-                (array) $paths
-            );
+            array_merge(self::$prefixDirsPsr4[$prefix], (array) $paths);
         }
         }
     }
     }
 
 
-    // 注册命名空间别名
+    /**
+     * 注册命名空间别名
+     * @access public
+     * @param  array|string $namespace 命名空间
+     * @param  string       $original  源文件
+     * @return void
+     */
     public static function addNamespaceAlias($namespace, $original = '')
     public static function addNamespaceAlias($namespace, $original = '')
     {
     {
         if (is_array($namespace)) {
         if (is_array($namespace)) {
@@ -236,32 +273,58 @@ class Loader
         }
         }
     }
     }
 
 
-    // 注册自动加载机制
-    public static function register($autoload = '')
+    /**
+     * 注册自动加载机制
+     * @access public
+     * @param  callable $autoload 自动加载处理方法
+     * @return void
+     */
+    public static function register($autoload = null)
     {
     {
         // 注册系统自动加载
         // 注册系统自动加载
         spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
         spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
+
+        // Composer 自动加载支持
+        if (is_dir(VENDOR_PATH . 'composer')) {
+            if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . 'composer' . DS . 'autoload_static.php')) {
+                require VENDOR_PATH . 'composer' . DS . 'autoload_static.php';
+
+                $declaredClass = get_declared_classes();
+                $composerClass = array_pop($declaredClass);
+
+                foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {
+                    if (property_exists($composerClass, $attr)) {
+                        self::${$attr} = $composerClass::${$attr};
+                    }
+                }
+            } else {
+                self::registerComposerLoader();
+            }
+        }
+
         // 注册命名空间定义
         // 注册命名空间定义
         self::addNamespace([
         self::addNamespace([
             'think'    => LIB_PATH . 'think' . DS,
             'think'    => LIB_PATH . 'think' . DS,
             'behavior' => LIB_PATH . 'behavior' . DS,
             'behavior' => LIB_PATH . 'behavior' . DS,
             'traits'   => LIB_PATH . 'traits' . DS,
             'traits'   => LIB_PATH . 'traits' . DS,
         ]);
         ]);
+
         // 加载类库映射文件
         // 加载类库映射文件
         if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {
         if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {
             self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
             self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
         }
         }
 
 
-        // Composer自动加载支持
-        if (is_dir(VENDOR_PATH . 'composer')) {
-            self::registerComposerLoader();
-        }
+        self::loadComposerAutoloadFiles();
 
 
-        // 自动加载extend目录
+        // 自动加载 extend 目录
         self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
         self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
     }
     }
 
 
-    // 注册composer自动加载
+    /**
+     * 注册 composer 自动加载
+     * @access private
+     * @return void
+     */
     private static function registerComposerLoader()
     private static function registerComposerLoader()
     {
     {
         if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {
         if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {
@@ -286,28 +349,36 @@ class Loader
         }
         }
 
 
         if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {
         if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {
-            $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php';
-            foreach ($includeFiles as $fileIdentifier => $file) {
-                if (empty(self::$autoloadFiles[$fileIdentifier])) {
-                    __require_file($file);
-                    self::$autoloadFiles[$fileIdentifier] = true;
-                }
+            self::$files = require VENDOR_PATH . 'composer/autoload_files.php';
+        }
+    }
+
+    // 加载composer autofile文件
+    public static function loadComposerAutoloadFiles()
+    {
+        foreach (self::$files as $fileIdentifier => $file) {
+            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+                __require_file($file);
+
+                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
             }
             }
         }
         }
     }
     }
 
 
     /**
     /**
-     * 导入所需的类库 同java的Import 本函数有缓存功能
-     * @param string $class   类库命名空间字符串
-     * @param string $baseUrl 起始路径
-     * @param string $ext     导入的文件扩展名
-     * @return boolean
+     * 导入所需的类库 同 Java 的 Import 本函数有缓存功能
+     * @access public
+     * @param  string $class   类库命名空间字符串
+     * @param  string $baseUrl 起始路径
+     * @param  string $ext     导入的文件扩展名
+     * @return bool
      */
      */
     public static function import($class, $baseUrl = '', $ext = EXT)
     public static function import($class, $baseUrl = '', $ext = EXT)
     {
     {
         static $_file = [];
         static $_file = [];
         $key          = $class . $baseUrl;
         $key          = $class . $baseUrl;
         $class        = str_replace(['.', '#'], [DS, '.'], $class);
         $class        = str_replace(['.', '#'], [DS, '.'], $class);
+
         if (isset($_file[$key])) {
         if (isset($_file[$key])) {
             return true;
             return true;
         }
         }
@@ -319,7 +390,7 @@ class Loader
                 // 注册的命名空间
                 // 注册的命名空间
                 $baseUrl = self::$prefixDirsPsr4[$name . '\\'];
                 $baseUrl = self::$prefixDirsPsr4[$name . '\\'];
             } elseif ('@' == $name) {
             } elseif ('@' == $name) {
-                //加载当前模块应用类库
+                // 加载当前模块应用类库
                 $baseUrl = App::$modulePath;
                 $baseUrl = App::$modulePath;
             } elseif (is_dir(EXTEND_PATH . $name)) {
             } elseif (is_dir(EXTEND_PATH . $name)) {
                 $baseUrl = EXTEND_PATH . $name . DS;
                 $baseUrl = EXTEND_PATH . $name . DS;
@@ -330,11 +401,11 @@ class Loader
         } elseif (substr($baseUrl, -1) != DS) {
         } elseif (substr($baseUrl, -1) != DS) {
             $baseUrl .= DS;
             $baseUrl .= DS;
         }
         }
-        // 如果类存在 则导入类库文件
+
+        // 如果类存在则导入类库文件
         if (is_array($baseUrl)) {
         if (is_array($baseUrl)) {
             foreach ($baseUrl as $path) {
             foreach ($baseUrl as $path) {
-                $filename = $path . DS . $class . $ext;
-                if (is_file($filename)) {
+                if (is_file($filename = $path . DS . $class . $ext)) {
                     break;
                     break;
                 }
                 }
             }
             }
@@ -342,137 +413,154 @@ class Loader
             $filename = $baseUrl . $class . $ext;
             $filename = $baseUrl . $class . $ext;
         }
         }
 
 
-        if (!empty($filename) && is_file($filename)) {
-            // 开启调试模式Win环境严格区分大小写
-            if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) {
-                return false;
-            }
+        if (!empty($filename) &&
+            is_file($filename) &&
+            (!IS_WIN || pathinfo($filename, PATHINFO_FILENAME) == pathinfo(realpath($filename), PATHINFO_FILENAME))
+        ) {
             __include_file($filename);
             __include_file($filename);
             $_file[$key] = true;
             $_file[$key] = true;
+
             return true;
             return true;
         }
         }
+
         return false;
         return false;
     }
     }
 
 
     /**
     /**
      * 实例化(分层)模型
      * 实例化(分层)模型
-     * @param string $name         Model名称
-     * @param string $layer        业务层名称
-     * @param bool   $appendSuffix 是否添加类名后缀
-     * @param string $common       公共模块名
+     * @access public
+     * @param  string $name         Model名称
+     * @param  string $layer        业务层名称
+     * @param  bool   $appendSuffix 是否添加类名后缀
+     * @param  string $common       公共模块名
      * @return object
      * @return object
      * @throws ClassNotFoundException
      * @throws ClassNotFoundException
      */
      */
     public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
     public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
     {
     {
-        $guid = $name . $layer;
-        if (isset(self::$instance[$guid])) {
-            return self::$instance[$guid];
-        }
-        if (false !== strpos($name, '\\')) {
-            $class  = $name;
-            $module = Request::instance()->module();
-        } else {
-            if (strpos($name, '/')) {
-                list($module, $name) = explode('/', $name, 2);
-            } else {
-                $module = Request::instance()->module();
-            }
-            $class = self::parseClass($module, $layer, $name, $appendSuffix);
+        $uid = $name . $layer;
+
+        if (isset(self::$instance[$uid])) {
+            return self::$instance[$uid];
         }
         }
+
+        list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
+
         if (class_exists($class)) {
         if (class_exists($class)) {
             $model = new $class();
             $model = new $class();
         } else {
         } else {
             $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
             $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
+
             if (class_exists($class)) {
             if (class_exists($class)) {
                 $model = new $class();
                 $model = new $class();
             } else {
             } else {
                 throw new ClassNotFoundException('class not exists:' . $class, $class);
                 throw new ClassNotFoundException('class not exists:' . $class, $class);
             }
             }
         }
         }
-        self::$instance[$guid] = $model;
-        return $model;
+
+        return self::$instance[$uid] = $model;
     }
     }
 
 
     /**
     /**
      * 实例化(分层)控制器 格式:[模块名/]控制器名
      * 实例化(分层)控制器 格式:[模块名/]控制器名
-     * @param string $name         资源地址
-     * @param string $layer        控制层名称
-     * @param bool   $appendSuffix 是否添加类名后缀
-     * @param string $empty        空控制器名称
+     * @access public
+     * @param  string $name         资源地址
+     * @param  string $layer        控制层名称
+     * @param  bool   $appendSuffix 是否添加类名后缀
+     * @param  string $empty        空控制器名称
      * @return object
      * @return object
      * @throws ClassNotFoundException
      * @throws ClassNotFoundException
      */
      */
     public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
     public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
     {
     {
-        if (false !== strpos($name, '\\')) {
-            $class  = $name;
-            $module = Request::instance()->module();
-        } else {
-            if (strpos($name, '/')) {
-                list($module, $name) = explode('/', $name);
-            } else {
-                $module = Request::instance()->module();
-            }
-            $class = self::parseClass($module, $layer, $name, $appendSuffix);
-        }
+        list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
+
         if (class_exists($class)) {
         if (class_exists($class)) {
             return App::invokeClass($class);
             return App::invokeClass($class);
-        } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {
-            return new $emptyClass(Request::instance());
-        } else {
-            throw new ClassNotFoundException('class not exists:' . $class, $class);
         }
         }
+
+        if ($empty) {
+            $emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix);
+
+            if (class_exists($emptyClass)) {
+                return new $emptyClass(Request::instance());
+            }
+        }
+
+        throw new ClassNotFoundException('class not exists:' . $class, $class);
     }
     }
 
 
     /**
     /**
      * 实例化验证类 格式:[模块名/]验证器名
      * 实例化验证类 格式:[模块名/]验证器名
-     * @param string $name         资源地址
-     * @param string $layer        验证层名称
-     * @param bool   $appendSuffix 是否添加类名后缀
-     * @param string $common       公共模块名
+     * @access public
+     * @param  string $name         资源地址
+     * @param  string $layer        验证层名称
+     * @param  bool   $appendSuffix 是否添加类名后缀
+     * @param  string $common       公共模块名
      * @return object|false
      * @return object|false
      * @throws ClassNotFoundException
      * @throws ClassNotFoundException
      */
      */
     public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
     public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
     {
     {
         $name = $name ?: Config::get('default_validate');
         $name = $name ?: Config::get('default_validate');
+
         if (empty($name)) {
         if (empty($name)) {
             return new Validate;
             return new Validate;
         }
         }
-        $guid = $name . $layer;
-        if (isset(self::$instance[$guid])) {
-            return self::$instance[$guid];
-        }
-        if (false !== strpos($name, '\\')) {
-            $class  = $name;
-            $module = Request::instance()->module();
-        } else {
-            if (strpos($name, '/')) {
-                list($module, $name) = explode('/', $name);
-            } else {
-                $module = Request::instance()->module();
-            }
-            $class = self::parseClass($module, $layer, $name, $appendSuffix);
+
+        $uid = $name . $layer;
+        if (isset(self::$instance[$uid])) {
+            return self::$instance[$uid];
         }
         }
+
+        list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix);
+
         if (class_exists($class)) {
         if (class_exists($class)) {
             $validate = new $class;
             $validate = new $class;
         } else {
         } else {
             $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
             $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
+
             if (class_exists($class)) {
             if (class_exists($class)) {
                 $validate = new $class;
                 $validate = new $class;
             } else {
             } else {
                 throw new ClassNotFoundException('class not exists:' . $class, $class);
                 throw new ClassNotFoundException('class not exists:' . $class, $class);
             }
             }
         }
         }
-        self::$instance[$guid] = $validate;
-        return $validate;
+
+        return self::$instance[$uid] = $validate;
+    }
+
+    /**
+     * 解析模块和类名
+     * @access protected
+     * @param  string $name         资源地址
+     * @param  string $layer        验证层名称
+     * @param  bool   $appendSuffix 是否添加类名后缀
+     * @return array
+     */
+    protected static function getModuleAndClass($name, $layer, $appendSuffix)
+    {
+        if (false !== strpos($name, '\\')) {
+            $module = Request::instance()->module();
+            $class  = $name;
+        } else {
+            if (strpos($name, '/')) {
+                list($module, $name) = explode('/', $name, 2);
+            } else {
+                $module = Request::instance()->module();
+            }
+
+            $class = self::parseClass($module, $layer, $name, $appendSuffix);
+        }
+
+        return [$module, $class];
     }
     }
 
 
     /**
     /**
      * 数据库初始化 并取得数据库类实例
      * 数据库初始化 并取得数据库类实例
-     * @param mixed         $config 数据库配置
-     * @param bool|string   $name 连接标识 true 强制重新连接
+     * @access public
+     * @param  mixed       $config 数据库配置
+     * @param  bool|string $name   连接标识 true 强制重新连接
      * @return \think\db\Connection
      * @return \think\db\Connection
      */
      */
     public static function db($config = [], $name = false)
     public static function db($config = [], $name = false)
@@ -482,10 +570,11 @@ class Loader
 
 
     /**
     /**
      * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
      * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
-     * @param string       $url          调用地址
-     * @param string|array $vars         调用参数 支持字符串和数组
-     * @param string       $layer        要调用的控制层名称
-     * @param bool         $appendSuffix 是否添加类名后缀
+     * @access public
+     * @param  string       $url          调用地址
+     * @param  string|array $vars         调用参数 支持字符串和数组
+     * @param  string       $layer        要调用的控制层名称
+     * @param  bool         $appendSuffix 是否添加类名后缀
      * @return mixed
      * @return mixed
      */
      */
     public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
     public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
@@ -494,6 +583,7 @@ class Loader
         $action = $info['basename'];
         $action = $info['basename'];
         $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
         $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
         $class  = self::controller($module, $layer, $appendSuffix);
         $class  = self::controller($module, $layer, $appendSuffix);
+
         if ($class) {
         if ($class) {
             if (is_scalar($vars)) {
             if (is_scalar($vars)) {
                 if (strpos($vars, '=')) {
                 if (strpos($vars, '=')) {
@@ -502,16 +592,20 @@ class Loader
                     $vars = [$vars];
                     $vars = [$vars];
                 }
                 }
             }
             }
+
             return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
             return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
         }
         }
+
+        return false;
     }
     }
 
 
     /**
     /**
      * 字符串命名风格转换
      * 字符串命名风格转换
-     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
-     * @param string  $name 字符串
-     * @param integer $type 转换类型
-     * @param bool    $ucfirst 首字母是否大写(驼峰规则)
+     * type 0 将 Java 风格转换为 C 的风格 1 将 C 风格转换为 Java 的风格
+     * @access public
+     * @param  string  $name    字符串
+     * @param  integer $type    转换类型
+     * @param  bool    $ucfirst 首字母是否大写(驼峰规则)
      * @return string
      * @return string
      */
      */
     public static function parseName($name, $type = 0, $ucfirst = true)
     public static function parseName($name, $type = 0, $ucfirst = true)
@@ -520,31 +614,38 @@ class Loader
             $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
             $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                 return strtoupper($match[1]);
                 return strtoupper($match[1]);
             }, $name);
             }, $name);
+
             return $ucfirst ? ucfirst($name) : lcfirst($name);
             return $ucfirst ? ucfirst($name) : lcfirst($name);
-        } else {
-            return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
         }
         }
+
+        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
     }
     }
 
 
     /**
     /**
      * 解析应用类的类名
      * 解析应用类的类名
-     * @param string $module 模块名
-     * @param string $layer  层名 controller model ...
-     * @param string $name   类名
-     * @param bool   $appendSuffix
+     * @access public
+     * @param  string $module       模块名
+     * @param  string $layer        层名 controller model ...
+     * @param  string $name         类名
+     * @param  bool   $appendSuffix 是否添加类名后缀
      * @return string
      * @return string
      */
      */
     public static function parseClass($module, $layer, $name, $appendSuffix = false)
     public static function parseClass($module, $layer, $name, $appendSuffix = false)
     {
     {
-        $name  = str_replace(['/', '.'], '\\', $name);
-        $array = explode('\\', $name);
-        $class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');
+
+        $array = explode('\\', str_replace(['/', '.'], '\\', $name));
+        $class = self::parseName(array_pop($array), 1);
+        $class = $class . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');
         $path  = $array ? implode('\\', $array) . '\\' : '';
         $path  = $array ? implode('\\', $array) . '\\' : '';
-        return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
+
+        return App::$namespace . '\\' .
+            ($module ? $module . '\\' : '') .
+            $layer . '\\' . $path . $class;
     }
     }
 
 
     /**
     /**
      * 初始化类的实例
      * 初始化类的实例
+     * @access public
      * @return void
      * @return void
      */
      */
     public static function clearInstance()
     public static function clearInstance()
@@ -553,10 +654,11 @@ class Loader
     }
     }
 }
 }
 
 
+// 作用范围隔离
+
 /**
 /**
- * 作用范围隔离
- *
- * @param $file
+ * include
+ * @param  string $file 文件路径
  * @return mixed
  * @return mixed
  */
  */
 function __include_file($file)
 function __include_file($file)
@@ -564,6 +666,11 @@ function __include_file($file)
     return include $file;
     return include $file;
 }
 }
 
 
+/**
+ * require
+ * @param  string $file 文件路径
+ * @return mixed
+ */
 function __require_file($file)
 function __require_file($file)
 {
 {
     return require $file;
     return require $file;

+ 102 - 78
thinkphp/library/think/Log.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -17,12 +17,12 @@ use think\exception\ClassNotFoundException;
  * Class Log
  * Class Log
  * @package think
  * @package think
  *
  *
- * @method void log($msg) static
- * @method void error($msg) static
- * @method void info($msg) static
- * @method void sql($msg) static
- * @method void notice($msg) static
- * @method void alert($msg) static
+ * @method void log($msg) static 记录一般日志
+ * @method void error($msg) static 记录错误日志
+ * @method void info($msg) static 记录一般信息日志
+ * @method void sql($msg) static 记录 SQL 查询日志
+ * @method void notice($msg) static 记录提示日志
+ * @method void alert($msg) static 记录报警日志
  */
  */
 class Log
 class Log
 {
 {
@@ -34,41 +34,60 @@ class Log
     const ALERT  = 'alert';
     const ALERT  = 'alert';
     const DEBUG  = 'debug';
     const DEBUG  = 'debug';
 
 
-    // 日志信息
+    /**
+     * @var array 日志信息
+     */
     protected static $log = [];
     protected static $log = [];
-    // 配置参数
+
+    /**
+     * @var array 配置参数
+     */
     protected static $config = [];
     protected static $config = [];
-    // 日志类型
+
+    /**
+     * @var array 日志类型
+     */
     protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
     protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
-    // 日志写入驱动
+
+    /**
+     * @var log\driver\File|log\driver\Test|log\driver\Socket 日志写入驱动
+     */
     protected static $driver;
     protected static $driver;
 
 
-    // 当前日志授权key
+    /**
+     * @var string 当前日志授权 key
+     */
     protected static $key;
     protected static $key;
 
 
     /**
     /**
      * 日志初始化
      * 日志初始化
-     * @param array $config
+     * @access public
+     * @param  array $config 配置参数
+     * @return void
      */
      */
     public static function init($config = [])
     public static function init($config = [])
     {
     {
-        $type         = isset($config['type']) ? $config['type'] : 'File';
-        $class        = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
+        $type  = isset($config['type']) ? $config['type'] : 'File';
+        $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
+
         self::$config = $config;
         self::$config = $config;
         unset($config['type']);
         unset($config['type']);
+
         if (class_exists($class)) {
         if (class_exists($class)) {
             self::$driver = new $class($config);
             self::$driver = new $class($config);
         } else {
         } else {
             throw new ClassNotFoundException('class not exists:' . $class, $class);
             throw new ClassNotFoundException('class not exists:' . $class, $class);
         }
         }
+
         // 记录初始化信息
         // 记录初始化信息
         App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');
         App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');
     }
     }
 
 
     /**
     /**
      * 获取日志信息
      * 获取日志信息
-     * @param string $type 信息类型
-     * @return array
+     * @access public
+     * @param  string $type 信息类型
+     * @return array|string
      */
      */
     public static function getLog($type = '')
     public static function getLog($type = '')
     {
     {
@@ -77,21 +96,22 @@ class Log
 
 
     /**
     /**
      * 记录调试信息
      * 记录调试信息
-     * @param mixed  $msg  调试信息
-     * @param string $type 信息类型
+     * @access public
+     * @param  mixed  $msg  调试信息
+     * @param  string $type 信息类型
      * @return void
      * @return void
      */
      */
     public static function record($msg, $type = 'log')
     public static function record($msg, $type = 'log')
     {
     {
         self::$log[$type][] = $msg;
         self::$log[$type][] = $msg;
-        if (IS_CLI) {
-            // 命令行下面日志写入改进
-            self::save();
-        }
+
+        // 命令行下面日志写入改进
+        IS_CLI && self::save();
     }
     }
 
 
     /**
     /**
      * 清空日志信息
      * 清空日志信息
+     * @access public
      * @return void
      * @return void
      */
      */
     public static function clear()
     public static function clear()
@@ -100,8 +120,9 @@ class Log
     }
     }
 
 
     /**
     /**
-     * 当前日志记录的授权key
-     * @param string $key 授权key
+     * 设置当前日志记录的授权 key
+     * @access public
+     * @param  string $key 授权 key
      * @return void
      * @return void
      */
      */
     public static function key($key)
     public static function key($key)
@@ -111,102 +132,105 @@ class Log
 
 
     /**
     /**
      * 检查日志写入权限
      * 检查日志写入权限
-     * @param array $config 当前日志配置参数
+     * @access public
+     * @param  array $config 当前日志配置参数
      * @return bool
      * @return bool
      */
      */
     public static function check($config)
     public static function check($config)
     {
     {
-        if (self::$key && !empty($config['allow_key']) && !in_array(self::$key, $config['allow_key'])) {
-            return false;
-        }
-        return true;
+        return !self::$key || empty($config['allow_key']) || in_array(self::$key, $config['allow_key']);
     }
     }
 
 
     /**
     /**
      * 保存调试信息
      * 保存调试信息
+     * @access public
      * @return bool
      * @return bool
      */
      */
     public static function save()
     public static function save()
     {
     {
-        if (!empty(self::$log)) {
-            if (is_null(self::$driver)) {
-                self::init(Config::get('log'));
-            }
+        // 没有需要保存的记录则直接返回
+        if (empty(self::$log)) {
+            return true;
+        }
 
 
-            if (!self::check(self::$config)) {
-                // 检测日志写入权限
-                return false;
-            }
+        is_null(self::$driver) && self::init(Config::get('log'));
 
 
-            if (empty(self::$config['level'])) {
-                // 获取全部日志
-                $log = self::$log;
-                if (!App::$debug && isset($log['debug'])) {
-                    unset($log['debug']);
-                }
-            } else {
-                // 记录允许级别
-                $log = [];
-                foreach (self::$config['level'] as $level) {
-                    if (isset(self::$log[$level])) {
-                        $log[$level] = self::$log[$level];
-                    }
+        // 检测日志写入权限
+        if (!self::check(self::$config)) {
+            return false;
+        }
+
+        if (empty(self::$config['level'])) {
+            // 获取全部日志
+            $log = self::$log;
+            if (!App::$debug && isset($log['debug'])) {
+                unset($log['debug']);
+            }
+        } else {
+            // 记录允许级别
+            $log = [];
+            foreach (self::$config['level'] as $level) {
+                if (isset(self::$log[$level])) {
+                    $log[$level] = self::$log[$level];
                 }
                 }
             }
             }
+        }
 
 
-            $result = self::$driver->save($log);
-            if ($result) {
-                self::$log = [];
-            }
-            Hook::listen('log_write_done', $log);
-            return $result;
+        if ($result = self::$driver->save($log, true)) {
+            self::$log = [];
         }
         }
-        return true;
+
+        Hook::listen('log_write_done', $log);
+
+        return $result;
     }
     }
 
 
     /**
     /**
      * 实时写入日志信息 并支持行为
      * 实时写入日志信息 并支持行为
-     * @param mixed  $msg   调试信息
-     * @param string $type  信息类型
-     * @param bool   $force 是否强制写入
+     * @access public
+     * @param  mixed  $msg   调试信息
+     * @param  string $type  信息类型
+     * @param  bool   $force 是否强制写入
      * @return bool
      * @return bool
      */
      */
     public static function write($msg, $type = 'log', $force = false)
     public static function write($msg, $type = 'log', $force = false)
     {
     {
         $log = self::$log;
         $log = self::$log;
-        // 封装日志信息
-        if (true === $force || empty(self::$config['level'])) {
-            $log[$type][] = $msg;
-        } elseif (in_array($type, self::$config['level'])) {
-            $log[$type][] = $msg;
-        } else {
+
+        // 如果不是强制写入,而且信息类型不在可记录的类别中则直接返回 false 不做记录
+        if (true !== $force && !empty(self::$config['level']) && !in_array($type, self::$config['level'])) {
             return false;
             return false;
         }
         }
 
 
-        // 监听log_write
+        // 封装日志信息
+        $log[$type][] = $msg;
+
+        // 监听 log_write
         Hook::listen('log_write', $log);
         Hook::listen('log_write', $log);
-        if (is_null(self::$driver)) {
-            self::init(Config::get('log'));
-        }
+
+        is_null(self::$driver) && self::init(Config::get('log'));
+
         // 写入日志
         // 写入日志
-        $result = self::$driver->save($log);
-        if ($result) {
+        if ($result = self::$driver->save($log, false)) {
             self::$log = [];
             self::$log = [];
         }
         }
+
         return $result;
         return $result;
     }
     }
 
 
     /**
     /**
-     * 静态调用
-     * @param $method
-     * @param $args
-     * @return mixed
+     * 静态方法调用
+     * @access public
+     * @param  string $method 调用方法
+     * @param  mixed  $args   参数
+     * @return void
      */
      */
     public static function __callStatic($method, $args)
     public static function __callStatic($method, $args)
     {
     {
         if (in_array($method, self::$type)) {
         if (in_array($method, self::$type)) {
             array_push($args, $method);
             array_push($args, $method);
-            return call_user_func_array('\\think\\Log::record', $args);
+
+            call_user_func_array('\\think\\Log::record', $args);
         }
         }
     }
     }
 
 

+ 181 - 43
thinkphp/library/think/Model.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -57,6 +57,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     protected $pk;
     protected $pk;
     // 数据表字段信息 留空则自动获取
     // 数据表字段信息 留空则自动获取
     protected $field = [];
     protected $field = [];
+    // 数据排除字段
+    protected $except = [];
+    // 数据废弃字段
+    protected $disuse = [];
     // 只读字段
     // 只读字段
     protected $readonly = [];
     protected $readonly = [];
     // 显示属性
     // 显示属性
@@ -90,6 +94,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     protected $type = [];
     protected $type = [];
     // 是否为更新数据
     // 是否为更新数据
     protected $isUpdate = false;
     protected $isUpdate = false;
+    // 是否使用Replace
+    protected $replace = false;
+    // 是否强制更新所有数据
+    protected $force = false;
     // 更新条件
     // 更新条件
     protected $updateWhere;
     protected $updateWhere;
     // 验证失败是否抛出异常
     // 验证失败是否抛出异常
@@ -110,6 +118,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
      */
      */
     protected static $initialized = [];
     protected static $initialized = [];
 
 
+    /**
+     * 是否从主库读取(主从分布式有效)
+     * @var array
+     */
+    protected static $readMaster;
+
     /**
     /**
      * 构造方法
      * 构造方法
      * @access public
      * @access public
@@ -122,6 +136,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         } else {
         } else {
             $this->data = $data;
             $this->data = $data;
         }
         }
+
+        if ($this->disuse) {
+            // 废弃字段
+            foreach ((array) $this->disuse as $key) {
+                if (array_key_exists($key, $this->data)) {
+                    unset($this->data[$key]);
+                }
+            }
+        }
+
         // 记录原始数据
         // 记录原始数据
         $this->origin = $this->data;
         $this->origin = $this->data;
 
 
@@ -155,6 +179,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         $this->initialize();
         $this->initialize();
     }
     }
 
 
+    /**
+     * 是否从主库读取数据(主从分布有效)
+     * @access public
+     * @param  bool     $all 是否所有模型生效
+     * @return $this
+     */
+    public function readMaster($all = false)
+    {
+        $model = $all ? '*' : $this->class;
+
+        static::$readMaster[$model] = true;
+        return $this;
+    }
+
     /**
     /**
      * 创建模型的查询对象
      * 创建模型的查询对象
      * @access protected
      * @access protected
@@ -176,7 +214,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         $con = Db::connect($connection);
         $con = Db::connect($connection);
         // 设置当前模型 确保查询返回模型对象
         // 设置当前模型 确保查询返回模型对象
         $queryClass = $this->query ?: $con->getConfig('query');
         $queryClass = $this->query ?: $con->getConfig('query');
-        $query      = new $queryClass($con, $this->class);
+        $query      = new $queryClass($con, $this);
+
+        if (isset(static::$readMaster['*']) || isset(static::$readMaster[$this->class])) {
+            $query->master(true);
+        }
 
 
         // 设置当前数据表和模型名
         // 设置当前数据表和模型名
         if (!empty($this->table)) {
         if (!empty($this->table)) {
@@ -192,6 +234,19 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         return $query;
         return $query;
     }
     }
 
 
+    /**
+     * 创建新的模型实例
+     * @access public
+     * @param  array|object $data 数据
+     * @param  bool         $isUpdate 是否为更新
+     * @param  mixed        $where 更新条件
+     * @return Model
+     */
+    public function newInstance($data = [], $isUpdate = false, $where = null)
+    {
+        return (new static($data))->isUpdate($isUpdate, $where);
+    }
+
     /**
     /**
      * 获取当前模型的查询对象
      * 获取当前模型的查询对象
      * @access public
      * @access public
@@ -262,7 +317,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     public function setParent($model)
     public function setParent($model)
     {
     {
         $this->parent = $model;
         $this->parent = $model;
-
         return $this;
         return $this;
     }
     }
 
 
@@ -337,6 +391,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         return $this;
         return $this;
     }
     }
 
 
+    /**
+     * 更新是否强制写入数据 而不做比较
+     * @access public
+     * @param bool $force
+     * @return $this
+     */
+    public function force($force = true)
+    {
+        $this->force = $force;
+        return $this;
+    }
+
     /**
     /**
      * 修改器 设置数据对象值
      * 修改器 设置数据对象值
      * @access public
      * @access public
@@ -572,7 +638,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
      */
      */
     protected function getRelationData(Relation $modelRelation)
     protected function getRelationData(Relation $modelRelation)
     {
     {
-        if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) {
+        if ($this->parent && !$modelRelation->isSelfRelation() && get_class($modelRelation->getModel()) == get_class($this->parent)) {
             $value = $this->parent;
             $value = $this->parent;
         } else {
         } else {
             // 首先获取关联数据
             // 首先获取关联数据
@@ -639,7 +705,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                 $value = empty($value) ? new \stdClass() : json_decode($value);
                 $value = empty($value) ? new \stdClass() : json_decode($value);
                 break;
                 break;
             case 'serialize':
             case 'serialize':
-                $value = unserialize($value);
+                try {
+                    $value = unserialize($value);
+                } catch (\Exception $e) {
+                    $value = null;
+                }
                 break;
                 break;
             default:
             default:
                 if (false !== strpos($type, '\\')) {
                 if (false !== strpos($type, '\\')) {
@@ -692,7 +762,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                 if (isset($this->data[$key])) {
                 if (isset($this->data[$key])) {
                     throw new Exception('bind attr has exists:' . $key);
                     throw new Exception('bind attr has exists:' . $key);
                 } else {
                 } else {
-                    $this->data[$key] = $model->$attr;
+                    $this->data[$key] = $model->getAttr($attr);
                 }
                 }
             }
             }
         }
         }
@@ -826,7 +896,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                     $relation   = $this->getAttr($key);
                     $relation   = $this->getAttr($key);
                     $item[$key] = $relation->append([$attr])->toArray();
                     $item[$key] = $relation->append([$attr])->toArray();
                 } else {
                 } else {
-                    $item[$name] = $this->getAttr($name);
+                    $relation = Loader::parseName($name, 1, false);
+                    if (method_exists($this, $relation)) {
+                        $modelRelation = $this->$relation();
+                        $value         = $this->getRelationData($modelRelation);
+
+                        if (method_exists($modelRelation, 'getBindAttr')) {
+                            $bindAttr = $modelRelation->getBindAttr();
+                            if ($bindAttr) {
+                                foreach ($bindAttr as $key => $attr) {
+                                    $key = is_numeric($key) ? $attr : $key;
+                                    if (isset($this->data[$key])) {
+                                        throw new Exception('bind attr has exists:' . $key);
+                                    } else {
+                                        $item[$key] = $value ? $value->getAttr($attr) : null;
+                                    }
+                                }
+                                continue;
+                            }
+                        }
+                        $item[$name] = $value;
+                    } else {
+                        $item[$name] = $this->getAttr($name);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -923,6 +1015,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         return false;
         return false;
     }
     }
 
 
+    /**
+     * 新增数据是否使用Replace
+     * @access public
+     * @param  bool $replace
+     * @return $this
+     */
+    public function replace($replace = true)
+    {
+        $this->replace = $replace;
+        return $this;
+    }
+
     /**
     /**
      * 保存当前数据对象
      * 保存当前数据对象
      * @access public
      * @access public
@@ -938,19 +1042,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             $data     = [];
             $data     = [];
         }
         }
 
 
+        // 数据自动验证
         if (!empty($data)) {
         if (!empty($data)) {
-            // 数据自动验证
             if (!$this->validateData($data)) {
             if (!$this->validateData($data)) {
                 return false;
                 return false;
             }
             }
+
             // 数据对象赋值
             // 数据对象赋值
             foreach ($data as $key => $value) {
             foreach ($data as $key => $value) {
                 $this->setAttr($key, $value, $data);
                 $this->setAttr($key, $value, $data);
             }
             }
-            if (!empty($where)) {
-                $this->isUpdate    = true;
-                $this->updateWhere = $where;
-            }
+        }
+
+        if (!empty($where)) {
+            $this->isUpdate    = true;
+            $this->updateWhere = $where;
         }
         }
 
 
         // 自动关联写入
         // 自动关联写入
@@ -1021,12 +1127,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                 }
                 }
             }
             }
 
 
-            if (is_string($pk) && isset($data[$pk])) {
-                if (!isset($where[$pk])) {
-                    unset($where);
-                    $where[$pk] = $data[$pk];
+            $array = [];
+
+            foreach ((array) $pk as $key) {
+                if (isset($data[$key])) {
+                    $array[$key] = $data[$key];
+                    unset($data[$key]);
                 }
                 }
-                unset($data[$pk]);
+            }
+
+            if (!empty($array)) {
+                $where = $array;
             }
             }
 
 
             // 检测字段
             // 检测字段
@@ -1068,16 +1179,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             // 检测字段
             // 检测字段
             $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));
             $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));
             if (!empty($allowFields)) {
             if (!empty($allowFields)) {
-                $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data);
+                $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data, $this->replace, false, $sequence);
             } else {
             } else {
-                $result = $this->getQuery()->insert($this->data);
+                $result = $this->getQuery()->insert($this->data, $this->replace, false, $sequence);
             }
             }
 
 
             // 获取自动增长主键
             // 获取自动增长主键
-            if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
-                $insertId = $this->getQuery()->getLastInsID($sequence);
-                if ($insertId) {
-                    $this->data[$pk] = $insertId;
+            if ($result && $insertId = $this->getQuery()->getLastInsID($sequence)) {
+                foreach ((array) $pk as $key) {
+                    if (!isset($this->data[$key]) || '' == $this->data[$key]) {
+                        $this->data[$key] = $insertId;
+                    }
                 }
                 }
             }
             }
 
 
@@ -1114,10 +1226,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             if ($this->autoWriteTimestamp) {
             if ($this->autoWriteTimestamp) {
                 array_push($field, $this->createTime, $this->updateTime);
                 array_push($field, $this->createTime, $this->updateTime);
             }
             }
+        } elseif (!empty($this->except)) {
+            $fields      = $this->getQuery()->getTableInfo('', 'fields');
+            $field       = array_diff($fields, (array) $this->except);
+            $this->field = $field;
         } else {
         } else {
             $field = [];
             $field = [];
         }
         }
 
 
+        if ($this->disuse) {
+            // 废弃字段
+            $field = array_diff($field, (array) $this->disuse);
+        }
         return $field;
         return $field;
     }
     }
 
 
@@ -1143,12 +1263,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
      */
      */
     public function getChangedData()
     public function getChangedData()
     {
     {
-        $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
-            if ((empty($a) || empty($b)) && $a !== $b) {
-                return 1;
-            }
-            return is_object($a) || $a != $b ? 1 : 0;
-        });
+        if ($this->force) {
+            $data = $this->data;
+        } else {
+            $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
+                if ((empty($a) || empty($b)) && $a !== $b) {
+                    return 1;
+                }
+                return is_object($a) || $a != $b ? 1 : 0;
+            });
+        }
 
 
         if (!empty($this->readonly)) {
         if (!empty($this->readonly)) {
             // 只读字段不允许更新
             // 只读字段不允许更新
@@ -1254,14 +1378,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
                 $auto = true;
                 $auto = true;
             }
             }
             foreach ($dataSet as $key => $data) {
             foreach ($dataSet as $key => $data) {
-                if (!empty($auto) && isset($data[$pk])) {
+                if ($this->isUpdate || (!empty($auto) && isset($data[$pk]))) {
                     $result[$key] = self::update($data, [], $this->field);
                     $result[$key] = self::update($data, [], $this->field);
                 } else {
                 } else {
                     $result[$key] = self::create($data, $this->field);
                     $result[$key] = self::create($data, $this->field);
                 }
                 }
             }
             }
             $db->commit();
             $db->commit();
-            return $result;
+            return $this->toCollection($result);
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             $db->rollback();
             $db->rollback();
             throw $e;
             throw $e;
@@ -1271,7 +1395,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     /**
     /**
      * 设置允许写入的字段
      * 设置允许写入的字段
      * @access public
      * @access public
-     * @param mixed $field 允许写入的字段 如果为true只允许写入数据表字段
+     * @param string|array $field 允许写入的字段 如果为true只允许写入数据表字段
      * @return $this
      * @return $this
      */
      */
     public function allowField($field)
     public function allowField($field)
@@ -1283,6 +1407,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
         return $this;
         return $this;
     }
     }
 
 
+    /**
+     * 设置排除写入的字段
+     * @access public
+     * @param string|array $field 排除允许写入的字段
+     * @return $this
+     */
+    public function except($field)
+    {
+        if (is_string($field)) {
+            $field = explode(',', $field);
+        }
+        $this->except = $field;
+        return $this;
+    }
+
     /**
     /**
      * 设置只读字段
      * 设置只读字段
      * @access public
      * @access public
@@ -1621,14 +1760,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     {
     {
         $model = new static();
         $model = new static();
         $query = $model->db();
         $query = $model->db();
-        if (is_array($data) && key($data) !== 0) {
+        if (empty($data) && 0 !== $data) {
+            return 0;
+        } elseif (is_array($data) && key($data) !== 0) {
             $query->where($data);
             $query->where($data);
             $data = null;
             $data = null;
         } elseif ($data instanceof \Closure) {
         } elseif ($data instanceof \Closure) {
             call_user_func_array($data, [ & $query]);
             call_user_func_array($data, [ & $query]);
             $data = null;
             $data = null;
-        } elseif (empty($data) && 0 !== $data) {
-            return 0;
         }
         }
         $resultSet = $query->select($data);
         $resultSet = $query->select($data);
         $count     = 0;
         $count     = 0;
@@ -1704,13 +1843,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     /**
     /**
      * 根据关联条件查询当前模型
      * 根据关联条件查询当前模型
      * @access public
      * @access public
-     * @param string $relation 关联方法名
-     * @param mixed  $where    查询条件(数组或者闭包)
+     * @param  string $relation 关联方法名
+     * @param  mixed  $where    查询条件(数组或者闭包)
+     * @param  mixed  $fields   字段
      * @return Relation|Query
      * @return Relation|Query
      */
      */
-    public static function hasWhere($relation, $where = [])
+    public static function hasWhere($relation, $where = [], $fields = null)
     {
     {
-        return (new static())->$relation()->hasWhere($where);
+        return (new static())->$relation()->hasWhere($where, $fields);
     }
     }
 
 
     /**
     /**
@@ -1976,7 +2116,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             $trace = debug_backtrace(false, 2);
             $trace = debug_backtrace(false, 2);
             $morph = Loader::parseName($trace[1]['function']);
             $morph = Loader::parseName($trace[1]['function']);
         }
         }
-        $type = $type ?: Loader::parseName($this->name);
+        $type = $type ?: get_class($this);
         if (is_array($morph)) {
         if (is_array($morph)) {
             list($morphType, $foreignKey) = $morph;
             list($morphType, $foreignKey) = $morph;
         } else {
         } else {
@@ -2002,7 +2142,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
             $trace = debug_backtrace(false, 2);
             $trace = debug_backtrace(false, 2);
             $morph = Loader::parseName($trace[1]['function']);
             $morph = Loader::parseName($trace[1]['function']);
         }
         }
-        $type = $type ?: Loader::parseName($this->name);
+        $type = $type ?: get_class($this);
         if (is_array($morph)) {
         if (is_array($morph)) {
             list($morphType, $foreignKey) = $morph;
             list($morphType, $foreignKey) = $morph;
         } else {
         } else {
@@ -2040,7 +2180,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     public function __call($method, $args)
     public function __call($method, $args)
     {
     {
         $query = $this->db(true, false);
         $query = $this->db(true, false);
-
         if (method_exists($this, 'scope' . $method)) {
         if (method_exists($this, 'scope' . $method)) {
             // 动态调用命名范围
             // 动态调用命名范围
             $method = 'scope' . $method;
             $method = 'scope' . $method;
@@ -2056,7 +2195,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
     {
     {
         $model = new static();
         $model = new static();
         $query = $model->db();
         $query = $model->db();
-
         if (method_exists($model, 'scope' . $method)) {
         if (method_exists($model, 'scope' . $method)) {
             // 动态调用命名范围
             // 动态调用命名范围
             $method = 'scope' . $method;
             $method = 'scope' . $method;

+ 11 - 3
thinkphp/library/think/Paginator.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -128,7 +128,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
         }
         }
         $url = $path;
         $url = $path;
         if (!empty($parameters)) {
         if (!empty($parameters)) {
-            $url .= '?' . urldecode(http_build_query($parameters, null, '&'));
+            $url .= '?' . http_build_query($parameters, null, '&');
         }
         }
         return $url . $this->buildFragment();
         return $url . $this->buildFragment();
     }
     }
@@ -395,7 +395,15 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
 
 
     public function __call($name, $arguments)
     public function __call($name, $arguments)
     {
     {
-        return call_user_func_array([$this->getCollection(), $name], $arguments);
+        $collection = $this->getCollection();
+
+        $result = call_user_func_array([$collection, $name], $arguments);
+
+        if ($result === $collection) {
+            return $this;
+        }
+
+        return $result;
     }
     }
 
 
 }
 }

+ 133 - 88
thinkphp/library/think/Request.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -121,6 +121,11 @@ class Request
     protected $cache;
     protected $cache;
     // 缓存是否检查
     // 缓存是否检查
     protected $isCheckCache;
     protected $isCheckCache;
+    /**
+     * 是否合并Param
+     * @var bool
+     */
+    protected $mergeParam = false;
 
 
     /**
     /**
      * 构造函数
      * 构造函数
@@ -155,8 +160,8 @@ class Request
     /**
     /**
      * Hook 方法注入
      * Hook 方法注入
      * @access public
      * @access public
-     * @param string|array  $method 方法名
-     * @param mixed         $callback callable
+     * @param string|array $method   方法名
+     * @param mixed        $callback callable
      * @return void
      * @return void
      */
      */
     public static function hook($method, $callback = null)
     public static function hook($method, $callback = null)
@@ -182,16 +187,28 @@ class Request
         return self::$instance;
         return self::$instance;
     }
     }
 
 
+    /**
+     * 销毁当前请求对象
+     * @access public
+     * @return void
+     */
+    public static function destroy()
+    {
+        if (!is_null(self::$instance)) {
+            self::$instance = null;
+        }
+    }
+
     /**
     /**
      * 创建一个URL请求
      * 创建一个URL请求
      * @access public
      * @access public
-     * @param string    $uri URL地址
-     * @param string    $method 请求类型
-     * @param array     $params 请求参数
-     * @param array     $cookie
-     * @param array     $files
-     * @param array     $server
-     * @param string    $content
+     * @param string $uri    URL地址
+     * @param string $method 请求类型
+     * @param array  $params 请求参数
+     * @param array  $cookie
+     * @param array  $files
+     * @param array  $server
+     * @param string $content
      * @return \think\Request
      * @return \think\Request
      */
      */
     public static function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null)
     public static function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null)
@@ -232,7 +249,7 @@ class Request
             parse_str(html_entity_decode($info['query']), $query);
             parse_str(html_entity_decode($info['query']), $query);
             if (!empty($params)) {
             if (!empty($params)) {
                 $params      = array_replace($query, $params);
                 $params      = array_replace($query, $params);
-                $queryString = http_build_query($query, '', '&');
+                $queryString = http_build_query($params, '', '&');
             } else {
             } else {
                 $params      = $query;
                 $params      = $query;
                 $queryString = $info['query'];
                 $queryString = $info['query'];
@@ -479,8 +496,8 @@ class Request
     /**
     /**
      * 设置资源类型
      * 设置资源类型
      * @access public
      * @access public
-     * @param string|array  $type 资源类型名
-     * @param string        $val 资源类型
+     * @param string|array $type 资源类型名
+     * @param string       $val  资源类型
      * @return void
      * @return void
      */
      */
     public function mimeType($type, $val = '')
     public function mimeType($type, $val = '')
@@ -495,22 +512,28 @@ class Request
     /**
     /**
      * 当前的请求类型
      * 当前的请求类型
      * @access public
      * @access public
-     * @param bool $method  true 获取原始请求类型
+     * @param bool $method true 获取原始请求类型
      * @return string
      * @return string
      */
      */
     public function method($method = false)
     public function method($method = false)
     {
     {
         if (true === $method) {
         if (true === $method) {
             // 获取原始请求类型
             // 获取原始请求类型
-            return IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);
+            return $this->server('REQUEST_METHOD') ?: 'GET';
         } elseif (!$this->method) {
         } elseif (!$this->method) {
             if (isset($_POST[Config::get('var_method')])) {
             if (isset($_POST[Config::get('var_method')])) {
-                $this->method = strtoupper($_POST[Config::get('var_method')]);
-                $this->{$this->method}($_POST);
+                $method = strtoupper($_POST[Config::get('var_method')]);
+                if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) {
+                    $this->method = $method;
+                    $this->{$this->method}($_POST);
+                } else {
+                    $this->method = 'POST';
+                }
+                unset($_POST[Config::get('var_method')]);
             } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
             } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
                 $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
                 $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
             } else {
             } else {
-                $this->method = IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);
+                $this->method = $this->server('REQUEST_METHOD') ?: 'GET';
             }
             }
         }
         }
         return $this->method;
         return $this->method;
@@ -609,14 +632,14 @@ class Request
     /**
     /**
      * 获取当前请求的参数
      * 获取当前请求的参数
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param mixed         $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function param($name = '', $default = null, $filter = '')
     public function param($name = '', $default = null, $filter = '')
     {
     {
-        if (empty($this->param)) {
+        if (empty($this->mergeParam)) {
             $method = $this->method(true);
             $method = $this->method(true);
             // 自动获取请求变量
             // 自动获取请求变量
             switch ($method) {
             switch ($method) {
@@ -632,7 +655,8 @@ class Request
                     $vars = [];
                     $vars = [];
             }
             }
             // 当前请求参数和URL地址中的参数合并
             // 当前请求参数和URL地址中的参数合并
-            $this->param = array_merge($this->get(false), $vars, $this->route(false));
+            $this->param      = array_merge($this->param, $this->get(false), $vars, $this->route(false));
+            $this->mergeParam = true;
         }
         }
         if (true === $name) {
         if (true === $name) {
             // 获取包含文件上传信息的数组
             // 获取包含文件上传信息的数组
@@ -646,15 +670,16 @@ class Request
     /**
     /**
      * 设置获取路由参数
      * 设置获取路由参数
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param mixed         $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function route($name = '', $default = null, $filter = '')
     public function route($name = '', $default = null, $filter = '')
     {
     {
         if (is_array($name)) {
         if (is_array($name)) {
             $this->param        = [];
             $this->param        = [];
+            $this->mergeParam   = false;
             return $this->route = array_merge($this->route, $name);
             return $this->route = array_merge($this->route, $name);
         }
         }
         return $this->input($this->route, $name, $default, $filter);
         return $this->input($this->route, $name, $default, $filter);
@@ -663,9 +688,9 @@ class Request
     /**
     /**
      * 设置获取GET参数
      * 设置获取GET参数
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param mixed         $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function get($name = '', $default = null, $filter = '')
     public function get($name = '', $default = null, $filter = '')
@@ -675,6 +700,7 @@ class Request
         }
         }
         if (is_array($name)) {
         if (is_array($name)) {
             $this->param      = [];
             $this->param      = [];
+            $this->mergeParam = false;
             return $this->get = array_merge($this->get, $name);
             return $this->get = array_merge($this->get, $name);
         }
         }
         return $this->input($this->get, $name, $default, $filter);
         return $this->input($this->get, $name, $default, $filter);
@@ -683,9 +709,9 @@ class Request
     /**
     /**
      * 设置获取POST参数
      * 设置获取POST参数
      * @access public
      * @access public
-     * @param string        $name 变量名
-     * @param mixed         $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string       $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function post($name = '', $default = null, $filter = '')
     public function post($name = '', $default = null, $filter = '')
@@ -700,6 +726,7 @@ class Request
         }
         }
         if (is_array($name)) {
         if (is_array($name)) {
             $this->param       = [];
             $this->param       = [];
+            $this->mergeParam  = false;
             return $this->post = array_merge($this->post, $name);
             return $this->post = array_merge($this->post, $name);
         }
         }
         return $this->input($this->post, $name, $default, $filter);
         return $this->input($this->post, $name, $default, $filter);
@@ -708,9 +735,9 @@ class Request
     /**
     /**
      * 设置获取PUT参数
      * 设置获取PUT参数
      * @access public
      * @access public
-     * @param string|array      $name 变量名
-     * @param mixed             $default 默认值
-     * @param string|array      $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function put($name = '', $default = null, $filter = '')
     public function put($name = '', $default = null, $filter = '')
@@ -725,6 +752,7 @@ class Request
         }
         }
         if (is_array($name)) {
         if (is_array($name)) {
             $this->param      = [];
             $this->param      = [];
+            $this->mergeParam = false;
             return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name);
             return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name);
         }
         }
 
 
@@ -734,9 +762,9 @@ class Request
     /**
     /**
      * 设置获取DELETE参数
      * 设置获取DELETE参数
      * @access public
      * @access public
-     * @param string|array      $name 变量名
-     * @param mixed             $default 默认值
-     * @param string|array      $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function delete($name = '', $default = null, $filter = '')
     public function delete($name = '', $default = null, $filter = '')
@@ -747,9 +775,9 @@ class Request
     /**
     /**
      * 设置获取PATCH参数
      * 设置获取PATCH参数
      * @access public
      * @access public
-     * @param string|array      $name 变量名
-     * @param mixed             $default 默认值
-     * @param string|array      $filter 过滤方法
+     * @param string|array $name    变量名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function patch($name = '', $default = null, $filter = '')
     public function patch($name = '', $default = null, $filter = '')
@@ -759,9 +787,9 @@ class Request
 
 
     /**
     /**
      * 获取request变量
      * 获取request变量
-     * @param string        $name 数据名称
-     * @param string        $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string       $name    数据名称
+     * @param string       $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function request($name = '', $default = null, $filter = '')
     public function request($name = '', $default = null, $filter = '')
@@ -771,6 +799,7 @@ class Request
         }
         }
         if (is_array($name)) {
         if (is_array($name)) {
             $this->param          = [];
             $this->param          = [];
+            $this->mergeParam     = false;
             return $this->request = array_merge($this->request, $name);
             return $this->request = array_merge($this->request, $name);
         }
         }
         return $this->input($this->request, $name, $default, $filter);
         return $this->input($this->request, $name, $default, $filter);
@@ -779,9 +808,9 @@ class Request
     /**
     /**
      * 获取session数据
      * 获取session数据
      * @access public
      * @access public
-     * @param string|array  $name 数据名称
-     * @param string        $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    数据名称
+     * @param string       $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function session($name = '', $default = null, $filter = '')
     public function session($name = '', $default = null, $filter = '')
@@ -798,9 +827,9 @@ class Request
     /**
     /**
      * 获取cookie参数
      * 获取cookie参数
      * @access public
      * @access public
-     * @param string|array  $name 数据名称
-     * @param string        $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    数据名称
+     * @param string       $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function cookie($name = '', $default = null, $filter = '')
     public function cookie($name = '', $default = null, $filter = '')
@@ -831,9 +860,9 @@ class Request
     /**
     /**
      * 获取server参数
      * 获取server参数
      * @access public
      * @access public
-     * @param string|array  $name 数据名称
-     * @param string        $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    数据名称
+     * @param string       $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function server($name = '', $default = null, $filter = '')
     public function server($name = '', $default = null, $filter = '')
@@ -909,9 +938,9 @@ class Request
 
 
     /**
     /**
      * 获取环境变量
      * 获取环境变量
-     * @param string|array  $name 数据名称
-     * @param string        $default 默认值
-     * @param string|array  $filter 过滤方法
+     * @param string|array $name    数据名称
+     * @param string       $default 默认值
+     * @param string|array $filter  过滤方法
      * @return mixed
      * @return mixed
      */
      */
     public function env($name = '', $default = null, $filter = '')
     public function env($name = '', $default = null, $filter = '')
@@ -928,8 +957,8 @@ class Request
     /**
     /**
      * 设置或者获取当前的Header
      * 设置或者获取当前的Header
      * @access public
      * @access public
-     * @param string|array  $name header名称
-     * @param string        $default 默认值
+     * @param string|array $name    header名称
+     * @param string       $default 默认值
      * @return string
      * @return string
      */
      */
     public function header($name = '', $default = null)
     public function header($name = '', $default = null)
@@ -967,10 +996,10 @@ class Request
 
 
     /**
     /**
      * 获取变量 支持过滤和默认值
      * 获取变量 支持过滤和默认值
-     * @param array         $data 数据源
-     * @param string|false  $name 字段名
-     * @param mixed         $default 默认值
-     * @param string|array  $filter 过滤函数
+     * @param array        $data    数据源
+     * @param string|false $name    字段名
+     * @param mixed        $default 默认值
+     * @param string|array $filter  过滤函数
      * @return mixed
      * @return mixed
      */
      */
     public function input($data = [], $name = '', $default = null, $filter = '')
     public function input($data = [], $name = '', $default = null, $filter = '')
@@ -1051,9 +1080,9 @@ class Request
 
 
     /**
     /**
      * 递归过滤给定的值
      * 递归过滤给定的值
-     * @param mixed     $value 键值
-     * @param mixed     $key 键名
-     * @param array     $filters 过滤方法+默认值
+     * @param mixed $value   键值
+     * @param mixed $key     键名
+     * @param array $filters 过滤方法+默认值
      * @return mixed
      * @return mixed
      */
      */
     private function filterValue(&$value, $key, $filters)
     private function filterValue(&$value, $key, $filters)
@@ -1093,7 +1122,7 @@ class Request
     public function filterExp(&$value)
     public function filterExp(&$value)
     {
     {
         // 过滤查询特殊字符
         // 过滤查询特殊字符
-        if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {
+        if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOT EXISTS|NOTEXISTS|EXISTS|NOT NULL|NOTNULL|NULL|BETWEEN TIME|NOT BETWEEN TIME|NOTBETWEEN TIME|NOTIN|NOT IN|IN)$/i', $value)) {
             $value .= ' ';
             $value .= ' ';
         }
         }
         // TODO 其他安全过滤
         // TODO 其他安全过滤
@@ -1138,9 +1167,9 @@ class Request
     /**
     /**
      * 是否存在某个请求参数
      * 是否存在某个请求参数
      * @access public
      * @access public
-     * @param string    $name 变量名
-     * @param string    $type 变量类型
-     * @param bool      $checkEmpty 是否检测空值
+     * @param string $name       变量名
+     * @param string $type       变量类型
+     * @param bool   $checkEmpty 是否检测空值
      * @return mixed
      * @return mixed
      */
      */
     public function has($name, $type = 'param', $checkEmpty = false)
     public function has($name, $type = 'param', $checkEmpty = false)
@@ -1164,8 +1193,8 @@ class Request
     /**
     /**
      * 获取指定的参数
      * 获取指定的参数
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param string        $type 变量类型
+     * @param string|array $name 变量名
+     * @param string       $type 变量类型
      * @return mixed
      * @return mixed
      */
      */
     public function only($name, $type = 'param')
     public function only($name, $type = 'param')
@@ -1186,8 +1215,8 @@ class Request
     /**
     /**
      * 排除指定参数获取
      * 排除指定参数获取
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param string        $type 变量类型
+     * @param string|array $name 变量名
+     * @param string       $type 变量类型
      * @return mixed
      * @return mixed
      */
      */
     public function except($name, $type = 'param')
     public function except($name, $type = 'param')
@@ -1229,7 +1258,7 @@ class Request
     /**
     /**
      * 当前是否Ajax请求
      * 当前是否Ajax请求
      * @access public
      * @access public
-     * @param bool $ajax  true 获取原始ajax请求
+     * @param bool $ajax true 获取原始ajax请求
      * @return bool
      * @return bool
      */
      */
     public function isAjax($ajax = false)
     public function isAjax($ajax = false)
@@ -1239,14 +1268,16 @@ class Request
         if (true === $ajax) {
         if (true === $ajax) {
             return $result;
             return $result;
         } else {
         } else {
-            return $this->param(Config::get('var_ajax')) ? true : $result;
+            $result           = $this->param(Config::get('var_ajax')) ? true : $result;
+            $this->mergeParam = false;
+            return $result;
         }
         }
     }
     }
 
 
     /**
     /**
      * 当前是否Pjax请求
      * 当前是否Pjax请求
      * @access public
      * @access public
-     * @param bool $pjax  true 获取原始pjax请求
+     * @param bool $pjax true 获取原始pjax请求
      * @return bool
      * @return bool
      */
      */
     public function isPjax($pjax = false)
     public function isPjax($pjax = false)
@@ -1255,17 +1286,19 @@ class Request
         if (true === $pjax) {
         if (true === $pjax) {
             return $result;
             return $result;
         } else {
         } else {
-            return $this->param(Config::get('var_pjax')) ? true : $result;
+            $result           = $this->param(Config::get('var_pjax')) ? true : $result;
+            $this->mergeParam = false;
+            return $result;
         }
         }
     }
     }
 
 
     /**
     /**
      * 获取客户端IP地址
      * 获取客户端IP地址
-     * @param integer   $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
-     * @param boolean   $adv 是否进行高级模式获取(有可能被伪装)
+     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
+     * @param boolean $adv  是否进行高级模式获取(有可能被伪装)
      * @return mixed
      * @return mixed
      */
      */
-    public function ip($type = 0, $adv = false)
+    public function ip($type = 0, $adv = true)
     {
     {
         $type      = $type ? 1 : 0;
         $type      = $type ? 1 : 0;
         static $ip = null;
         static $ip = null;
@@ -1273,7 +1306,11 @@ class Request
             return $ip[$type];
             return $ip[$type];
         }
         }
 
 
-        if ($adv) {
+        $httpAgentIp = Config::get('http_agent_ip');
+
+        if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) {
+            $ip = $_SERVER[$httpAgentIp];
+        } elseif ($adv) {
             if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
             if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                 $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                 $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                 $pos = array_search('unknown', $arr);
                 $pos = array_search('unknown', $arr);
@@ -1338,11 +1375,18 @@ class Request
     /**
     /**
      * 当前请求的host
      * 当前请求的host
      * @access public
      * @access public
+     * @param bool $strict true 仅仅获取HOST
      * @return string
      * @return string
      */
      */
-    public function host()
+    public function host($strict = false)
     {
     {
-        return $this->server('HTTP_HOST');
+        if (isset($_SERVER['HTTP_X_REAL_HOST'])) {
+            $host = $_SERVER['HTTP_X_REAL_HOST'];
+        } else {
+            $host = $this->server('HTTP_HOST');
+        }
+
+        return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host;
     }
     }
 
 
     /**
     /**
@@ -1412,7 +1456,7 @@ class Request
     /**
     /**
      * 设置或者获取当前请求的调度信息
      * 设置或者获取当前请求的调度信息
      * @access public
      * @access public
-     * @param array  $dispatch 调度信息
+     * @param array $dispatch 调度信息
      * @return array
      * @return array
      */
      */
     public function dispatch($dispatch = null)
     public function dispatch($dispatch = null)
@@ -1463,11 +1507,12 @@ class Request
      */
      */
     public function action($action = null)
     public function action($action = null)
     {
     {
-        if (!is_null($action)) {
+        if (!is_null($action) && !is_bool($action)) {
             $this->action = $action;
             $this->action = $action;
             return $this;
             return $this;
         } else {
         } else {
-            return $this->action ?: '';
+            $name = $this->action ?: '';
+            return true === $action ? $name : strtolower($name);
         }
         }
     }
     }
 
 
@@ -1531,7 +1576,7 @@ class Request
     /**
     /**
      * 设置当前地址的请求缓存
      * 设置当前地址的请求缓存
      * @access public
      * @access public
-     * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id
+     * @param string $key    缓存标识,支持变量规则 ,例如 item/:name/:id
      * @param mixed  $expire 缓存有效期
      * @param mixed  $expire 缓存有效期
      * @param array  $except 缓存排除
      * @param array  $except 缓存排除
      * @param string $tag    缓存标签
      * @param string $tag    缓存标签
@@ -1616,7 +1661,7 @@ class Request
      * 设置当前请求绑定的对象实例
      * 设置当前请求绑定的对象实例
      * @access public
      * @access public
      * @param string|array $name 绑定的对象标识
      * @param string|array $name 绑定的对象标识
-     * @param mixed  $obj 绑定的对象实例
+     * @param mixed        $obj  绑定的对象实例
      * @return mixed
      * @return mixed
      */
      */
     public function bind($name, $obj = null)
     public function bind($name, $obj = null)

+ 2 - 4
thinkphp/library/think/Response.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -69,9 +69,7 @@ class Response
      */
      */
     public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
     public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
     {
     {
-        $type = empty($type) ? 'null' : strtolower($type);
-
-        $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst($type);
+        $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
         if (class_exists($class)) {
         if (class_exists($class)) {
             $response = new $class($data, $code, $header, $options);
             $response = new $class($data, $code, $header, $options);
         } else {
         } else {

+ 180 - 138
thinkphp/library/think/Route.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -68,8 +68,8 @@ class Route
     /**
     /**
      * 注册变量规则
      * 注册变量规则
      * @access public
      * @access public
-     * @param string|array  $name 变量名
-     * @param string        $rule 变量规则
+     * @param string|array $name 变量名
+     * @param string       $rule 变量规则
      * @return void
      * @return void
      */
      */
     public static function pattern($name = null, $rule = '')
     public static function pattern($name = null, $rule = '')
@@ -84,10 +84,10 @@ class Route
     /**
     /**
      * 注册子域名部署规则
      * 注册子域名部署规则
      * @access public
      * @access public
-     * @param string|array  $domain 子域名
-     * @param mixed         $rule 路由规则
-     * @param array         $option 路由参数
-     * @param array         $pattern 变量规则
+     * @param string|array $domain  子域名
+     * @param mixed        $rule    路由规则
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function domain($domain, $rule = '', $option = [], $pattern = [])
     public static function domain($domain, $rule = '', $option = [], $pattern = [])
@@ -121,8 +121,8 @@ class Route
     /**
     /**
      * 设置路由绑定
      * 设置路由绑定
      * @access public
      * @access public
-     * @param mixed     $bind 绑定信息
-     * @param string    $type 绑定类型 默认为module 支持 namespace class controller
+     * @param mixed  $bind 绑定信息
+     * @param string $type 绑定类型 默认为module 支持 namespace class controller
      * @return mixed
      * @return mixed
      */
      */
     public static function bind($bind, $type = 'module')
     public static function bind($bind, $type = 'module')
@@ -133,8 +133,8 @@ class Route
     /**
     /**
      * 设置或者获取路由标识
      * 设置或者获取路由标识
      * @access public
      * @access public
-     * @param string|array     $name 路由命名标识 数组表示批量设置
-     * @param array            $value 路由地址及变量信息
+     * @param string|array $name  路由命名标识 数组表示批量设置
+     * @param array        $value 路由地址及变量信息
      * @return array
      * @return array
      */
      */
     public static function name($name = '', $value = null)
     public static function name($name = '', $value = null)
@@ -154,7 +154,7 @@ class Route
     /**
     /**
      * 读取路由绑定
      * 读取路由绑定
      * @access public
      * @access public
-     * @param string    $type 绑定类型
+     * @param string $type 绑定类型
      * @return mixed
      * @return mixed
      */
      */
     public static function getBind($type)
     public static function getBind($type)
@@ -165,8 +165,8 @@ class Route
     /**
     /**
      * 导入配置文件的路由规则
      * 导入配置文件的路由规则
      * @access public
      * @access public
-     * @param array     $rule 路由规则
-     * @param string    $type 请求类型
+     * @param array  $rule 路由规则
+     * @param string $type 请求类型
      * @return void
      * @return void
      */
      */
     public static function import(array $rule, $type = '*')
     public static function import(array $rule, $type = '*')
@@ -222,11 +222,11 @@ class Route
     /**
     /**
      * 注册路由规则
      * 注册路由规则
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param string    $type 请求类型
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param string       $type    请求类型
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = [])
     public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = [])
@@ -270,12 +270,12 @@ class Route
     /**
     /**
      * 设置路由规则
      * 设置路由规则
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param string    $type 请求类型
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
-     * @param string    $group 所属分组
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param string       $type    请求类型
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
+     * @param string       $group   所属分组
      * @return void
      * @return void
      */
      */
     protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '')
     protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '')
@@ -335,9 +335,9 @@ class Route
             if ('*' == $type) {
             if ('*' == $type) {
                 // 注册路由快捷方式
                 // 注册路由快捷方式
                 foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
                 foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
-                    if (self::$domain) {
+                    if (self::$domain && !isset(self::$rules['domain'][self::$domain][$method][$rule])) {
                         self::$rules['domain'][self::$domain][$method][$rule] = true;
                         self::$rules['domain'][self::$domain][$method][$rule] = true;
-                    } else {
+                    } elseif (!self::$domain && !isset(self::$rules[$method][$rule])) {
                         self::$rules[$method][$rule] = true;
                         self::$rules[$method][$rule] = true;
                     }
                     }
                 }
                 }
@@ -348,7 +348,7 @@ class Route
     /**
     /**
      * 设置当前执行的参数信息
      * 设置当前执行的参数信息
      * @access public
      * @access public
-     * @param array    $options 参数信息
+     * @param array $options 参数信息
      * @return mixed
      * @return mixed
      */
      */
     protected static function setOption($options = [])
     protected static function setOption($options = [])
@@ -369,7 +369,7 @@ class Route
     /**
     /**
      * 获取当前的分组信息
      * 获取当前的分组信息
      * @access public
      * @access public
-     * @param string    $type 分组信息名称 name option pattern
+     * @param string $type 分组信息名称 name option pattern
      * @return mixed
      * @return mixed
      */
      */
     public static function getGroup($type)
     public static function getGroup($type)
@@ -384,9 +384,9 @@ class Route
     /**
     /**
      * 设置当前的路由分组
      * 设置当前的路由分组
      * @access public
      * @access public
-     * @param string    $name 分组名称
-     * @param array     $option 分组路由参数
-     * @param array     $pattern 分组变量规则
+     * @param string $name    分组名称
+     * @param array  $option  分组路由参数
+     * @param array  $pattern 分组变量规则
      * @return void
      * @return void
      */
      */
     public static function setGroup($name, $option = [], $pattern = [])
     public static function setGroup($name, $option = [], $pattern = [])
@@ -399,10 +399,10 @@ class Route
     /**
     /**
      * 注册路由分组
      * 注册路由分组
      * @access public
      * @access public
-     * @param string|array      $name 分组名称或者参数
-     * @param array|\Closure    $routes 路由地址
-     * @param array             $option 路由参数
-     * @param array             $pattern 变量规则
+     * @param string|array   $name    分组名称或者参数
+     * @param array|\Closure $routes  路由地址
+     * @param array          $option  路由参数
+     * @param array          $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function group($name, $routes, $option = [], $pattern = [])
     public static function group($name, $routes, $option = [], $pattern = [])
@@ -487,10 +487,10 @@ class Route
     /**
     /**
      * 注册路由
      * 注册路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function any($rule, $route = '', $option = [], $pattern = [])
     public static function any($rule, $route = '', $option = [], $pattern = [])
@@ -501,10 +501,10 @@ class Route
     /**
     /**
      * 注册GET路由
      * 注册GET路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function get($rule, $route = '', $option = [], $pattern = [])
     public static function get($rule, $route = '', $option = [], $pattern = [])
@@ -515,10 +515,10 @@ class Route
     /**
     /**
      * 注册POST路由
      * 注册POST路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function post($rule, $route = '', $option = [], $pattern = [])
     public static function post($rule, $route = '', $option = [], $pattern = [])
@@ -529,10 +529,10 @@ class Route
     /**
     /**
      * 注册PUT路由
      * 注册PUT路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function put($rule, $route = '', $option = [], $pattern = [])
     public static function put($rule, $route = '', $option = [], $pattern = [])
@@ -543,10 +543,10 @@ class Route
     /**
     /**
      * 注册DELETE路由
      * 注册DELETE路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function delete($rule, $route = '', $option = [], $pattern = [])
     public static function delete($rule, $route = '', $option = [], $pattern = [])
@@ -557,10 +557,10 @@ class Route
     /**
     /**
      * 注册PATCH路由
      * 注册PATCH路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function patch($rule, $route = '', $option = [], $pattern = [])
     public static function patch($rule, $route = '', $option = [], $pattern = [])
@@ -571,10 +571,10 @@ class Route
     /**
     /**
      * 注册资源路由
      * 注册资源路由
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string|array $rule    路由规则
+     * @param string       $route   路由地址
+     * @param array        $option  路由参数
+     * @param array        $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function resource($rule, $route = '', $option = [], $pattern = [])
     public static function resource($rule, $route = '', $option = [], $pattern = [])
@@ -618,10 +618,10 @@ class Route
     /**
     /**
      * 注册控制器路由 操作方法对应不同的请求后缀
      * 注册控制器路由 操作方法对应不同的请求后缀
      * @access public
      * @access public
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param array     $option 路由参数
-     * @param array     $pattern 变量规则
+     * @param string $rule    路由规则
+     * @param string $route   路由地址
+     * @param array  $option  路由参数
+     * @param array  $pattern 变量规则
      * @return void
      * @return void
      */
      */
     public static function controller($rule, $route = '', $option = [], $pattern = [])
     public static function controller($rule, $route = '', $option = [], $pattern = [])
@@ -634,9 +634,9 @@ class Route
     /**
     /**
      * 注册别名路由
      * 注册别名路由
      * @access public
      * @access public
-     * @param string|array  $rule 路由别名
-     * @param string        $route 路由地址
-     * @param array         $option 路由参数
+     * @param string|array $rule   路由别名
+     * @param string       $route  路由地址
+     * @param array        $option 路由参数
      * @return void
      * @return void
      */
      */
     public static function alias($rule = null, $route = '', $option = [])
     public static function alias($rule = null, $route = '', $option = [])
@@ -651,8 +651,8 @@ class Route
     /**
     /**
      * 设置不同请求类型下面的方法前缀
      * 设置不同请求类型下面的方法前缀
      * @access public
      * @access public
-     * @param string    $method 请求类型
-     * @param string    $prefix 类型前缀
+     * @param string $method 请求类型
+     * @param string $prefix 类型前缀
      * @return void
      * @return void
      */
      */
     public static function setMethodPrefix($method, $prefix = '')
     public static function setMethodPrefix($method, $prefix = '')
@@ -667,8 +667,8 @@ class Route
     /**
     /**
      * rest方法定义和修改
      * rest方法定义和修改
      * @access public
      * @access public
-     * @param string        $name 方法名称
-     * @param array|bool    $resource 资源
+     * @param string|array $name     方法名称
+     * @param array|bool   $resource 资源
      * @return void
      * @return void
      */
      */
     public static function rest($name, $resource = [])
     public static function rest($name, $resource = [])
@@ -683,9 +683,9 @@ class Route
     /**
     /**
      * 注册未匹配路由规则后的处理
      * 注册未匹配路由规则后的处理
      * @access public
      * @access public
-     * @param string    $route 路由地址
-     * @param string    $method 请求类型
-     * @param array     $option 路由参数
+     * @param string $route  路由地址
+     * @param string $method 请求类型
+     * @param array  $option 路由参数
      * @return void
      * @return void
      */
      */
     public static function miss($route, $method = '*', $option = [])
     public static function miss($route, $method = '*', $option = [])
@@ -696,7 +696,7 @@ class Route
     /**
     /**
      * 注册一个自动解析的URL路由
      * 注册一个自动解析的URL路由
      * @access public
      * @access public
-     * @param string    $route 路由地址
+     * @param string $route 路由地址
      * @return void
      * @return void
      */
      */
     public static function auto($route)
     public static function auto($route)
@@ -726,9 +726,9 @@ class Route
     /**
     /**
      * 检测子域名部署
      * 检测子域名部署
      * @access public
      * @access public
-     * @param Request   $request Request请求对象
-     * @param array     $currentRules 当前路由规则
-     * @param string    $method 请求类型
+     * @param Request $request      Request请求对象
+     * @param array   $currentRules 当前路由规则
+     * @param string  $method       请求类型
      * @return void
      * @return void
      */
      */
     public static function checkDomain($request, &$currentRules, $method = 'get')
     public static function checkDomain($request, &$currentRules, $method = 'get')
@@ -737,7 +737,7 @@ class Route
         $rules = self::$rules['domain'];
         $rules = self::$rules['domain'];
         // 开启子域名部署 支持二级和三级域名
         // 开启子域名部署 支持二级和三级域名
         if (!empty($rules)) {
         if (!empty($rules)) {
-            $host = $request->host();
+            $host = $request->host(true);
             if (isset($rules[$host])) {
             if (isset($rules[$host])) {
                 // 完整域名或者IP配置
                 // 完整域名或者IP配置
                 $item = $rules[$host];
                 $item = $rules[$host];
@@ -827,14 +827,23 @@ class Route
     /**
     /**
      * 检测URL路由
      * 检测URL路由
      * @access public
      * @access public
-     * @param Request   $request Request请求对象
-     * @param string    $url URL地址
-     * @param string    $depr URL分隔符
-     * @param bool      $checkDomain 是否检测域名规则
+     * @param Request $request     Request请求对象
+     * @param string  $url         URL地址
+     * @param string  $depr        URL分隔符
+     * @param bool    $checkDomain 是否检测域名规则
      * @return false|array
      * @return false|array
      */
      */
     public static function check($request, $url, $depr = '/', $checkDomain = false)
     public static function check($request, $url, $depr = '/', $checkDomain = false)
     {
     {
+        //检查解析缓存
+        if (!App::$debug && Config::get('route_check_cache')) {
+            $key = self::getCheckCacheKey($request);
+            if (Cache::has($key)) {
+                list($rule, $route, $pathinfo, $option, $matches) = Cache::get($key);
+                return self::parseRule($rule, $route, $pathinfo, $option, $matches, true);
+            }
+        }
+
         // 分隔符替换 确保路由定义使用统一的分隔符
         // 分隔符替换 确保路由定义使用统一的分隔符
         $url = str_replace($depr, '|', $url);
         $url = str_replace($depr, '|', $url);
 
 
@@ -888,12 +897,12 @@ class Route
     /**
     /**
      * 检测路由规则
      * 检测路由规则
      * @access private
      * @access private
-     * @param Request   $request
-     * @param array     $rules 路由规则
-     * @param string    $url URL地址
-     * @param string    $depr URL分割符
-     * @param string    $group 路由分组名
-     * @param array     $options 路由参数(分组)
+     * @param Request $request
+     * @param array   $rules   路由规则
+     * @param string  $url     URL地址
+     * @param string  $depr    URL分割符
+     * @param string  $group   路由分组名
+     * @param array   $options 路由参数(分组)
      * @return mixed
      * @return mixed
      */
      */
     private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = [])
     private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = [])
@@ -971,9 +980,9 @@ class Route
     /**
     /**
      * 检测路由别名
      * 检测路由别名
      * @access private
      * @access private
-     * @param Request   $request
-     * @param string    $url URL地址
-     * @param string    $depr URL分隔符
+     * @param Request $request
+     * @param string  $url  URL地址
+     * @param string  $depr URL分隔符
      * @return mixed
      * @return mixed
      */
      */
     private static function checkRouteAlias($request, $url, $depr)
     private static function checkRouteAlias($request, $url, $depr)
@@ -1018,9 +1027,9 @@ class Route
     /**
     /**
      * 检测URL绑定
      * 检测URL绑定
      * @access private
      * @access private
-     * @param string    $url URL地址
-     * @param array     $rules 路由规则
-     * @param string    $depr URL分隔符
+     * @param string $url   URL地址
+     * @param array  $rules 路由规则
+     * @param string $depr  URL分隔符
      * @return mixed
      * @return mixed
      */
      */
     private static function checkUrlBind(&$url, &$rules, $depr = '/')
     private static function checkUrlBind(&$url, &$rules, $depr = '/')
@@ -1049,9 +1058,9 @@ class Route
     /**
     /**
      * 绑定到类
      * 绑定到类
      * @access public
      * @access public
-     * @param string    $url URL地址
-     * @param string    $class 类名(带命名空间)
-     * @param string    $depr URL分隔符
+     * @param string $url   URL地址
+     * @param string $class 类名(带命名空间)
+     * @param string $depr  URL分隔符
      * @return array
      * @return array
      */
      */
     public static function bindToClass($url, $class, $depr = '/')
     public static function bindToClass($url, $class, $depr = '/')
@@ -1068,9 +1077,9 @@ class Route
     /**
     /**
      * 绑定到命名空间
      * 绑定到命名空间
      * @access public
      * @access public
-     * @param string    $url URL地址
-     * @param string    $namespace 命名空间
-     * @param string    $depr URL分隔符
+     * @param string $url       URL地址
+     * @param string $namespace 命名空间
+     * @param string $depr      URL分隔符
      * @return array
      * @return array
      */
      */
     public static function bindToNamespace($url, $namespace, $depr = '/')
     public static function bindToNamespace($url, $namespace, $depr = '/')
@@ -1088,9 +1097,9 @@ class Route
     /**
     /**
      * 绑定到控制器类
      * 绑定到控制器类
      * @access public
      * @access public
-     * @param string    $url URL地址
-     * @param string    $controller 控制器名 (支持带模块名 index/user )
-     * @param string    $depr URL分隔符
+     * @param string $url        URL地址
+     * @param string $controller 控制器名 (支持带模块名 index/user )
+     * @param string $depr       URL分隔符
      * @return array
      * @return array
      */
      */
     public static function bindToController($url, $controller, $depr = '/')
     public static function bindToController($url, $controller, $depr = '/')
@@ -1107,9 +1116,9 @@ class Route
     /**
     /**
      * 绑定到模块/控制器
      * 绑定到模块/控制器
      * @access public
      * @access public
-     * @param string    $url URL地址
-     * @param string    $controller 控制器类名(带命名空间)
-     * @param string    $depr URL分隔符
+     * @param string $url        URL地址
+     * @param string $controller 控制器类名(带命名空间)
+     * @param string $depr       URL分隔符
      * @return array
      * @return array
      */
      */
     public static function bindToModule($url, $controller, $depr = '/')
     public static function bindToModule($url, $controller, $depr = '/')
@@ -1126,8 +1135,8 @@ class Route
     /**
     /**
      * 路由参数有效性检查
      * 路由参数有效性检查
      * @access private
      * @access private
-     * @param array     $option 路由参数
-     * @param Request   $request Request对象
+     * @param array   $option  路由参数
+     * @param Request $request Request对象
      * @return bool
      * @return bool
      */
      */
     private static function checkOption($option, $request)
     private static function checkOption($option, $request)
@@ -1153,12 +1162,12 @@ class Route
     /**
     /**
      * 检测路由规则
      * 检测路由规则
      * @access private
      * @access private
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param string    $url URL地址
-     * @param array     $pattern 变量规则
-     * @param array     $option 路由参数
-     * @param string    $depr URL分隔符(全局)
+     * @param string $rule    路由规则
+     * @param string $route   路由地址
+     * @param string $url     URL地址
+     * @param array  $pattern 变量规则
+     * @param array  $option  路由参数
+     * @param string $depr    URL分隔符(全局)
      * @return array|false
      * @return array|false
      */
      */
     private static function checkRule($rule, $route, $url, $pattern, $option, $depr)
     private static function checkRule($rule, $route, $url, $pattern, $option, $depr)
@@ -1200,9 +1209,9 @@ class Route
     /**
     /**
      * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...
      * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...
      * @access public
      * @access public
-     * @param string    $url URL地址
-     * @param string    $depr URL分隔符
-     * @param bool      $autoSearch 是否自动深度搜索控制器
+     * @param string $url        URL地址
+     * @param string $depr       URL分隔符
+     * @param bool   $autoSearch 是否自动深度搜索控制器
      * @return array
      * @return array
      */
      */
     public static function parseUrl($url, $depr = '/', $autoSearch = false)
     public static function parseUrl($url, $depr = '/', $autoSearch = false)
@@ -1269,7 +1278,7 @@ class Route
     /**
     /**
      * 解析URL的pathinfo参数和变量
      * 解析URL的pathinfo参数和变量
      * @access private
      * @access private
-     * @param string    $url URL地址
+     * @param string $url URL地址
      * @return array
      * @return array
      */
      */
     private static function parseUrlPath($url)
     private static function parseUrlPath($url)
@@ -1295,9 +1304,9 @@ class Route
     /**
     /**
      * 检测URL和规则路由是否匹配
      * 检测URL和规则路由是否匹配
      * @access private
      * @access private
-     * @param string    $url URL地址
-     * @param string    $rule 路由规则
-     * @param array     $pattern 变量规则
+     * @param string $url     URL地址
+     * @param string $rule    路由规则
+     * @param array  $pattern 变量规则
      * @return array|false
      * @return array|false
      */
      */
     private static function match($url, $rule, $pattern)
     private static function match($url, $rule, $pattern)
@@ -1370,16 +1379,28 @@ class Route
     /**
     /**
      * 解析规则路由
      * 解析规则路由
      * @access private
      * @access private
-     * @param string    $rule 路由规则
-     * @param string    $route 路由地址
-     * @param string    $pathinfo URL地址
-     * @param array     $option 路由参数
-     * @param array     $matches 匹配的变量
+     * @param string $rule      路由规则
+     * @param string $route     路由地址
+     * @param string $pathinfo  URL地址
+     * @param array  $option    路由参数
+     * @param array  $matches   匹配的变量
+     * @param bool   $fromCache 通过缓存解析
      * @return array
      * @return array
      */
      */
-    private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [])
+    private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [], $fromCache = false)
     {
     {
         $request = Request::instance();
         $request = Request::instance();
+
+        //保存解析缓存
+        if (Config::get('route_check_cache') && !$fromCache) {
+            try {
+                $key = self::getCheckCacheKey($request);
+                Cache::tag('route_check')->set($key, [$rule, $route, $pathinfo, $option, $matches]);
+            } catch (\Exception $e) {
+
+            }
+        }
+
         // 解析路由规则
         // 解析路由规则
         if ($rule) {
         if ($rule) {
             $rule = explode('/', $rule);
             $rule = explode('/', $rule);
@@ -1506,7 +1527,7 @@ class Route
             App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : '');
             App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : '');
         } else {
         } else {
             // 路由到模块/控制器/操作
             // 路由到模块/控制器/操作
-            $result = self::parseModule($route);
+            $result = self::parseModule($route, isset($option['convert']) ? $option['convert'] : false);
         }
         }
         // 开启请求缓存
         // 开启请求缓存
         if ($request->isGet() && isset($option['cache'])) {
         if ($request->isGet() && isset($option['cache'])) {
@@ -1526,10 +1547,11 @@ class Route
     /**
     /**
      * 解析URL地址为 模块/控制器/操作
      * 解析URL地址为 模块/控制器/操作
      * @access private
      * @access private
-     * @param string    $url URL地址
+     * @param string $url     URL地址
+     * @param bool   $convert 是否自动转换URL地址
      * @return array
      * @return array
      */
      */
-    private static function parseModule($url)
+    private static function parseModule($url, $convert = false)
     {
     {
         list($path, $var) = self::parseUrlPath($url);
         list($path, $var) = self::parseUrlPath($url);
         $action           = array_pop($path);
         $action           = array_pop($path);
@@ -1543,14 +1565,14 @@ class Route
         // 设置当前请求的路由变量
         // 设置当前请求的路由变量
         Request::instance()->route($var);
         Request::instance()->route($var);
         // 路由到模块/控制器/操作
         // 路由到模块/控制器/操作
-        return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false];
+        return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => $convert];
     }
     }
 
 
     /**
     /**
      * 解析URL地址中的参数Request对象
      * 解析URL地址中的参数Request对象
      * @access private
      * @access private
-     * @param string    $url 路由规则
-     * @param array     $var 变量
+     * @param string $url 路由规则
+     * @param array  $var 变量
      * @return void
      * @return void
      */
      */
     private static function parseUrlParams($url, &$var = [])
     private static function parseUrlParams($url, &$var = [])
@@ -1600,4 +1622,24 @@ class Route
         }
         }
         return $var;
         return $var;
     }
     }
+
+    /**
+     * 获取路由解析缓存的key
+     * @param Request $request
+     * @return string
+     */
+    private static function getCheckCacheKey(Request $request)
+    {
+        static $key;
+
+        if (empty($key)) {
+            if ($callback = Config::get('route_check_cache_key')) {
+                $key = call_user_func($callback, $request);
+            } else {
+                $key = "{$request->host(true)}|{$request->method()}|{$request->path()}";
+            }
+        }
+
+        return $key;
+    }
 }
 }

+ 1 - 1
thinkphp/library/think/Session.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 17 - 25
thinkphp/library/think/Template.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -12,6 +12,7 @@
 namespace think;
 namespace think;
 
 
 use think\exception\TemplateNotFoundException;
 use think\exception\TemplateNotFoundException;
+use think\template\TagLib;
 
 
 /**
 /**
  * ThinkPHP分离出来的模板引擎
  * ThinkPHP分离出来的模板引擎
@@ -63,12 +64,16 @@ class Template
      */
      */
     public function __construct(array $config = [])
     public function __construct(array $config = [])
     {
     {
-        $this->config['cache_path']   = TEMP_PATH;
-        $this->config                 = array_merge($this->config, $config);
-        $this->config['taglib_begin'] = $this->stripPreg($this->config['taglib_begin']);
-        $this->config['taglib_end']   = $this->stripPreg($this->config['taglib_end']);
-        $this->config['tpl_begin']    = $this->stripPreg($this->config['tpl_begin']);
-        $this->config['tpl_end']      = $this->stripPreg($this->config['tpl_end']);
+        $this->config['cache_path'] = TEMP_PATH;
+        $this->config               = array_merge($this->config, $config);
+
+        $this->config['taglib_begin_origin'] = $this->config['taglib_begin'];
+        $this->config['taglib_end_origin']   = $this->config['taglib_end'];
+
+        $this->config['taglib_begin'] = preg_quote($this->config['taglib_begin'], '/');
+        $this->config['taglib_end']   = preg_quote($this->config['taglib_end'], '/');
+        $this->config['tpl_begin']    = preg_quote($this->config['tpl_begin'], '/');
+        $this->config['tpl_end']      = preg_quote($this->config['tpl_end'], '/');
 
 
         // 初始化模板编译存储器
         // 初始化模板编译存储器
         $type          = $this->config['compile_type'] ? $this->config['compile_type'] : 'File';
         $type          = $this->config['compile_type'] ? $this->config['compile_type'] : 'File';
@@ -76,20 +81,6 @@ class Template
         $this->storage = new $class();
         $this->storage = new $class();
     }
     }
 
 
-    /**
-     * 字符串替换 避免正则混淆
-     * @access private
-     * @param string $str
-     * @return string
-     */
-    private function stripPreg($str)
-    {
-        return str_replace(
-            ['{', '}', '(', ')', '|', '[', ']', '-', '+', '*', '.', '^', '?'],
-            ['\{', '\}', '\(', '\)', '\|', '\[', '\]', '\-', '\+', '\*', '\.', '\^', '\?'],
-            $str);
-    }
-
     /**
     /**
      * 模板变量赋值
      * 模板变量赋值
      * @access public
      * @access public
@@ -121,7 +112,7 @@ class Template
      * 模板引擎配置项
      * 模板引擎配置项
      * @access public
      * @access public
      * @param array|string $config
      * @param array|string $config
-     * @return void|array
+     * @return string|void|array
      */
      */
     public function config($config)
     public function config($config)
     {
     {
@@ -184,7 +175,7 @@ class Template
         }
         }
         $template = $this->parseTemplateFile($template);
         $template = $this->parseTemplateFile($template);
         if ($template) {
         if ($template) {
-            $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($template) . '.' . ltrim($this->config['cache_suffix'], '.');
+            $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
             if (!$this->checkCache($cacheFile)) {
             if (!$this->checkCache($cacheFile)) {
                 // 缓存无效 重新模板编译
                 // 缓存无效 重新模板编译
                 $content = file_get_contents($template);
                 $content = file_get_contents($template);
@@ -235,7 +226,7 @@ class Template
      * @access public
      * @access public
      * @param mixed     $name 布局模板名称 false 则关闭布局
      * @param mixed     $name 布局模板名称 false 则关闭布局
      * @param string    $replace 布局模板内容替换标识
      * @param string    $replace 布局模板内容替换标识
-     * @return object
+     * @return Template
      */
      */
     public function layout($name, $replace = '')
     public function layout($name, $replace = '')
     {
     {
@@ -689,6 +680,7 @@ class Template
         } else {
         } else {
             $className = '\\think\\template\\taglib\\' . ucwords($tagLib);
             $className = '\\think\\template\\taglib\\' . ucwords($tagLib);
         }
         }
+        /** @var Taglib $tLib */
         $tLib = new $className($this);
         $tLib = new $className($this);
         $tLib->parseTag($content, $hide ? '' : $tagLib);
         $tLib->parseTag($content, $hide ? '' : $tagLib);
         return;
         return;
@@ -1071,7 +1063,7 @@ class Template
             } else {
             } else {
                 $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path'];
                 $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path'];
             }
             }
-            $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.');
+            $template = realpath($path . $template . '.' . ltrim($this->config['view_suffix'], '.'));
         }
         }
 
 
         if (is_file($template)) {
         if (is_file($template)) {

+ 15 - 10
thinkphp/library/think/Url.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -118,7 +118,7 @@ class Url
             $type = Route::getBind('type');
             $type = Route::getBind('type');
             if ($type) {
             if ($type) {
                 $bind = Route::getBind($type);
                 $bind = Route::getBind($type);
-                if (0 === strpos($url, $bind)) {
+                if ($bind && 0 === strpos($url, $bind)) {
                     $url = substr($url, strlen($bind) + 1);
                     $url = substr($url, strlen($bind) + 1);
                 }
                 }
             }
             }
@@ -135,7 +135,7 @@ class Url
         if (!empty($vars)) {
         if (!empty($vars)) {
             // 添加参数
             // 添加参数
             if (Config::get('url_common_param')) {
             if (Config::get('url_common_param')) {
-                $vars = urldecode(http_build_query($vars));
+                $vars = http_build_query($vars);
                 $url .= $suffix . '?' . $vars . $anchor;
                 $url .= $suffix . '?' . $vars . $anchor;
             } else {
             } else {
                 $paramType = Config::get('url_param_type');
                 $paramType = Config::get('url_param_type');
@@ -210,17 +210,21 @@ class Url
             }
             }
             $module = $module ? $module . '/' : '';
             $module = $module ? $module . '/' : '';
 
 
-            $controller = Loader::parseName($request->controller());
+            $controller = $request->controller();
             if ('' == $url) {
             if ('' == $url) {
                 // 空字符串输出当前的 模块/控制器/操作
                 // 空字符串输出当前的 模块/控制器/操作
-                $url = $module . $controller . '/' . $request->action();
+                $action = $request->action();
             } else {
             } else {
                 $path       = explode('/', $url);
                 $path       = explode('/', $url);
-                $action     = Config::get('url_convert') ? strtolower(array_pop($path)) : array_pop($path);
-                $controller = empty($path) ? $controller : (Config::get('url_convert') ? Loader::parseName(array_pop($path)) : array_pop($path));
+                $action     = array_pop($path);
+                $controller = empty($path) ? $controller : array_pop($path);
                 $module     = empty($path) ? $module : array_pop($path) . '/';
                 $module     = empty($path) ? $module : array_pop($path) . '/';
-                $url        = $module . $controller . '/' . $action;
             }
             }
+            if (Config::get('url_convert')) {
+                $action     = strtolower($action);
+                $controller = Loader::parseName($controller);
+            }
+            $url = $module . $controller . '/' . $action;
         }
         }
         return $url;
         return $url;
     }
     }
@@ -298,11 +302,12 @@ class Url
         foreach ($rule as $item) {
         foreach ($rule as $item) {
             list($url, $pattern, $domain, $suffix) = $item;
             list($url, $pattern, $domain, $suffix) = $item;
             if (empty($pattern)) {
             if (empty($pattern)) {
-                return [$url, $domain, $suffix];
+                return [rtrim($url, '$'), $domain, $suffix];
             }
             }
+            $type = Config::get('url_common_param');
             foreach ($pattern as $key => $val) {
             foreach ($pattern as $key => $val) {
                 if (isset($vars[$key])) {
                 if (isset($vars[$key])) {
-                    $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url);
+                    $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url);
                     unset($vars[$key]);
                     unset($vars[$key]);
                     $result = [$url, $domain, $suffix];
                     $result = [$url, $domain, $suffix];
                 } elseif (2 == $val) {
                 } elseif (2 == $val) {

+ 181 - 102
thinkphp/library/think/Validate.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -36,55 +36,56 @@ class Validate
 
 
     // 验证规则默认提示信息
     // 验证规则默认提示信息
     protected static $typeMsg = [
     protected static $typeMsg = [
-        'require'     => ':attribute不能为空',
-        'number'      => ':attribute必须是数字',
-        'integer'     => ':attribute必须是整数',
-        'float'       => ':attribute必须是浮点数',
-        'boolean'     => ':attribute必须是布尔值',
-        'email'       => ':attribute格式不符',
-        'array'       => ':attribute必须是数组',
-        'accepted'    => ':attribute必须是yes、on或者1',
-        'date'        => ':attribute格式不符合',
-        'file'        => ':attribute不是有效的上传文件',
-        'image'       => ':attribute不是有效的图像文件',
-        'alpha'       => ':attribute只能是字母',
-        'alphaNum'    => ':attribute只能是字母和数字',
-        'alphaDash'   => ':attribute只能是字母、数字和下划线_及破折号-',
-        'activeUrl'   => ':attribute不是有效的域名或者IP',
-        'chs'         => ':attribute只能是汉字',
-        'chsAlpha'    => ':attribute只能是汉字、字母',
-        'chsAlphaNum' => ':attribute只能是汉字、字母和数字',
-        'chsDash'     => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
-        'url'         => ':attribute不是有效的URL地址',
-        'ip'          => ':attribute不是有效的IP地址',
-        'dateFormat'  => ':attribute必须使用日期格式 :rule',
-        'in'          => ':attribute必须在 :rule 范围内',
-        'notIn'       => ':attribute不能在 :rule 范围内',
-        'between'     => ':attribute只能在 :1 - :2 之间',
-        'notBetween'  => ':attribute不能在 :1 - :2 之间',
-        'length'      => ':attribute长度不符合要求 :rule',
-        'max'         => ':attribute长度不能超过 :rule',
-        'min'         => ':attribute长度不能小于 :rule',
-        'after'       => ':attribute日期不能小于 :rule',
-        'before'      => ':attribute日期不能超过 :rule',
-        'expire'      => '不在有效期内 :rule',
-        'allowIp'     => '不允许的IP访问',
-        'denyIp'      => '禁止的IP访问',
-        'confirm'     => ':attribute和确认字段:2不一致',
-        'different'   => ':attribute和比较字段:2不能相同',
-        'egt'         => ':attribute必须大于等于 :rule',
-        'gt'          => ':attribute必须大于 :rule',
-        'elt'         => ':attribute必须小于等于 :rule',
-        'lt'          => ':attribute必须小于 :rule',
-        'eq'          => ':attribute必须等于 :rule',
-        'unique'      => ':attribute已存在',
-        'regex'       => ':attribute不符合指定规则',
-        'method'      => '无效的请求类型',
-        'token'       => '令牌数据无效',
-        'fileSize'    => '上传文件大小不符',
-        'fileExt'     => '上传文件后缀不符',
-        'fileMime'    => '上传文件类型不符',
-
+        'require'     => ':attribute require',
+        'number'      => ':attribute must be numeric',
+        'integer'     => ':attribute must be integer',
+        'float'       => ':attribute must be float',
+        'boolean'     => ':attribute must be bool',
+        'email'       => ':attribute not a valid email address',
+        'array'       => ':attribute must be a array',
+        'accepted'    => ':attribute must be yes,on or 1',
+        'date'        => ':attribute not a valid datetime',
+        'file'        => ':attribute not a valid file',
+        'image'       => ':attribute not a valid image',
+        'alpha'       => ':attribute must be alpha',
+        'alphaNum'    => ':attribute must be alpha-numeric',
+        'alphaDash'   => ':attribute must be alpha-numeric, dash, underscore',
+        'activeUrl'   => ':attribute not a valid domain or ip',
+        'chs'         => ':attribute must be chinese',
+        'chsAlpha'    => ':attribute must be chinese or alpha',
+        'chsAlphaNum' => ':attribute must be chinese,alpha-numeric',
+        'chsDash'     => ':attribute must be chinese,alpha-numeric,underscore, dash',
+        'url'         => ':attribute not a valid url',
+        'ip'          => ':attribute not a valid ip',
+        'dateFormat'  => ':attribute must be dateFormat of :rule',
+        'in'          => ':attribute must be in :rule',
+        'notIn'       => ':attribute be notin :rule',
+        'between'     => ':attribute must between :1 - :2',
+        'notBetween'  => ':attribute not between :1 - :2',
+        'length'      => 'size of :attribute must be :rule',
+        'max'         => 'max size of :attribute must be :rule',
+        'min'         => 'min size of :attribute must be :rule',
+        'after'       => ':attribute cannot be less than :rule',
+        'before'      => ':attribute cannot exceed :rule',
+        'afterWith'   => ':attribute cannot be less than :rule',
+        'beforeWith'  => ':attribute cannot exceed :rule',
+        'expire'      => ':attribute not within :rule',
+        'allowIp'     => 'access IP is not allowed',
+        'denyIp'      => 'access IP denied',
+        'confirm'     => ':attribute out of accord with :2',
+        'different'   => ':attribute cannot be same with :2',
+        'egt'         => ':attribute must greater than or equal :rule',
+        'gt'          => ':attribute must greater than :rule',
+        'elt'         => ':attribute must less than or equal :rule',
+        'lt'          => ':attribute must less than :rule',
+        'eq'          => ':attribute must equal :rule',
+        'unique'      => ':attribute has exists',
+        'regex'       => ':attribute not conform to the rules',
+        'method'      => 'invalid Request method',
+        'token'       => 'invalid token',
+        'fileSize'    => 'filesize not match',
+        'fileExt'     => 'extensions to upload is not allowed',
+        'fileMime'    => 'mimetype to upload is not allowed',
     ];
     ];
 
 
     // 当前验证场景
     // 当前验证场景
@@ -340,6 +341,41 @@ class Validate
         return !empty($this->error) ? false : true;
         return !empty($this->error) ? false : true;
     }
     }
 
 
+    /**
+     * 根据验证规则验证数据
+     * @access protected
+     * @param  mixed     $value 字段值
+     * @param  mixed     $rules 验证规则
+     * @return bool
+     */
+    protected function checkRule($value, $rules)
+    {
+        if ($rules instanceof \Closure) {
+            return call_user_func_array($rules, [$value]);
+        } elseif (is_string($rules)) {
+            $rules = explode('|', $rules);
+        }
+
+        foreach ($rules as $key => $rule) {
+            if ($rule instanceof \Closure) {
+                $result = call_user_func_array($rule, [$value]);
+            } else {
+                // 判断验证类型
+                list($type, $rule) = $this->getValidateType($key, $rule);
+
+                $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type];
+
+                $result = call_user_func_array($callback, [$value, $rule]);
+            }
+
+            if (true !== $result) {
+                return $result;
+            }
+        }
+
+        return true;
+    }
+
     /**
     /**
      * 验证单个字段规则
      * 验证单个字段规则
      * @access protected
      * @access protected
@@ -364,25 +400,7 @@ class Validate
                 $info   = is_numeric($key) ? '' : $key;
                 $info   = is_numeric($key) ? '' : $key;
             } else {
             } else {
                 // 判断验证类型
                 // 判断验证类型
-                if (is_numeric($key)) {
-                    if (strpos($rule, ':')) {
-                        list($type, $rule) = explode(':', $rule, 2);
-                        if (isset($this->alias[$type])) {
-                            // 判断别名
-                            $type = $this->alias[$type];
-                        }
-                        $info = $type;
-                    } elseif (method_exists($this, $rule)) {
-                        $type = $rule;
-                        $info = $rule;
-                        $rule = '';
-                    } else {
-                        $type = 'is';
-                        $info = $rule;
-                    }
-                } else {
-                    $info = $type = $key;
-                }
+                list($type, $rule, $info) = $this->getValidateType($key, $rule);
 
 
                 // 如果不是require 有数据才会行验证
                 // 如果不是require 有数据才会行验证
                 if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
                 if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
@@ -418,6 +436,39 @@ class Validate
         return $result;
         return $result;
     }
     }
 
 
+    /**
+     * 获取当前验证类型及规则
+     * @access public
+     * @param  mixed     $key
+     * @param  mixed     $rule
+     * @return array
+     */
+    protected function getValidateType($key, $rule)
+    {
+        // 判断验证类型
+        if (!is_numeric($key)) {
+            return [$key, $rule, $key];
+        }
+
+        if (strpos($rule, ':')) {
+            list($type, $rule) = explode(':', $rule, 2);
+            if (isset($this->alias[$type])) {
+                // 判断别名
+                $type = $this->alias[$type];
+            }
+            $info = $type;
+        } elseif (method_exists($this, $rule)) {
+            $type = $rule;
+            $info = $rule;
+            $rule = '';
+        } else {
+            $type = 'is';
+            $info = $rule;
+        }
+
+        return [$type, $rule, $info];
+    }
+
     /**
     /**
      * 验证是否和某个字段的值一致
      * 验证是否和某个字段的值一致
      * @access protected
      * @access protected
@@ -681,21 +732,17 @@ class Validate
      */
      */
     protected function fileExt($file, $rule)
     protected function fileExt($file, $rule)
     {
     {
-        if (!($file instanceof File)) {
-            return false;
-        }
-        if (is_string($rule)) {
-            $rule = explode(',', $rule);
-        }
         if (is_array($file)) {
         if (is_array($file)) {
             foreach ($file as $item) {
             foreach ($file as $item) {
-                if (!$item->checkExt($rule)) {
+                if (!($item instanceof File) || !$item->checkExt($rule)) {
                     return false;
                     return false;
                 }
                 }
             }
             }
             return true;
             return true;
-        } else {
+        } elseif ($file instanceof File) {
             return $file->checkExt($rule);
             return $file->checkExt($rule);
+        } else {
+            return false;
         }
         }
     }
     }
 
 
@@ -708,21 +755,17 @@ class Validate
      */
      */
     protected function fileMime($file, $rule)
     protected function fileMime($file, $rule)
     {
     {
-        if (!($file instanceof File)) {
-            return false;
-        }
-        if (is_string($rule)) {
-            $rule = explode(',', $rule);
-        }
         if (is_array($file)) {
         if (is_array($file)) {
             foreach ($file as $item) {
             foreach ($file as $item) {
-                if (!$item->checkMime($rule)) {
+                if (!($item instanceof File) || !$item->checkMime($rule)) {
                     return false;
                     return false;
                 }
                 }
             }
             }
             return true;
             return true;
-        } else {
+        } elseif ($file instanceof File) {
             return $file->checkMime($rule);
             return $file->checkMime($rule);
+        } else {
+            return false;
         }
         }
     }
     }
 
 
@@ -735,18 +778,17 @@ class Validate
      */
      */
     protected function fileSize($file, $rule)
     protected function fileSize($file, $rule)
     {
     {
-        if (!($file instanceof File)) {
-            return false;
-        }
         if (is_array($file)) {
         if (is_array($file)) {
             foreach ($file as $item) {
             foreach ($file as $item) {
-                if (!$item->checkSize($rule)) {
+                if (!($item instanceof File) || !$item->checkSize($rule)) {
                     return false;
                     return false;
                 }
                 }
             }
             }
             return true;
             return true;
-        } else {
+        } elseif ($file instanceof File) {
             return $file->checkSize($rule);
             return $file->checkSize($rule);
+        } else {
+            return false;
         }
         }
     }
     }
 
 
@@ -838,21 +880,26 @@ class Validate
             // 支持多个字段验证
             // 支持多个字段验证
             $fields = explode('^', $key);
             $fields = explode('^', $key);
             foreach ($fields as $key) {
             foreach ($fields as $key) {
-                $map[$key] = $data[$key];
+                if (isset($data[$key])) {
+                    $map[$key] = $data[$key];
+                }
             }
             }
         } elseif (strpos($key, '=')) {
         } elseif (strpos($key, '=')) {
             parse_str($key, $map);
             parse_str($key, $map);
-        } else {
+        } elseif (isset($data[$field])) {
             $map[$key] = $data[$field];
             $map[$key] = $data[$field];
+        } else {
+            $map = [];
         }
         }
 
 
-        $pk = strval(isset($rule[3]) ? $rule[3] : $db->getPk());
-        if (isset($rule[2])) {
-            $map[$pk] = ['neq', $rule[2]];
-        } elseif (isset($data[$pk])) {
-            $map[$pk] = ['neq', $data[$pk]];
+        $pk = isset($rule[3]) ? $rule[3] : $db->getPk();
+        if (is_string($pk)) {
+            if (isset($rule[2])) {
+                $map[$pk] = ['neq', $rule[2]];
+            } elseif (isset($data[$pk])) {
+                $map[$pk] = ['neq', $data[$pk]];
+            }
         }
         }
-
         if ($db->where($map)->field($pk)->find()) {
         if ($db->where($map)->field($pk)->find()) {
             return false;
             return false;
         }
         }
@@ -1072,9 +1119,10 @@ class Validate
      * @access protected
      * @access protected
      * @param mixed     $value  字段值
      * @param mixed     $value  字段值
      * @param mixed     $rule  验证规则
      * @param mixed     $rule  验证规则
+     * @param array     $data  数据
      * @return bool
      * @return bool
      */
      */
-    protected function after($value, $rule)
+    protected function after($value, $rule, $data)
     {
     {
         return strtotime($value) >= strtotime($rule);
         return strtotime($value) >= strtotime($rule);
     }
     }
@@ -1084,13 +1132,42 @@ class Validate
      * @access protected
      * @access protected
      * @param mixed     $value  字段值
      * @param mixed     $value  字段值
      * @param mixed     $rule  验证规则
      * @param mixed     $rule  验证规则
+     * @param array     $data  数据
      * @return bool
      * @return bool
      */
      */
-    protected function before($value, $rule)
+    protected function before($value, $rule, $data)
     {
     {
         return strtotime($value) <= strtotime($rule);
         return strtotime($value) <= strtotime($rule);
     }
     }
 
 
+    /**
+     * 验证日期字段
+     * @access protected
+     * @param mixed     $value  字段值
+     * @param mixed     $rule  验证规则
+     * @param array     $data  数据
+     * @return bool
+     */
+    protected function afterWith($value, $rule, $data)
+    {
+        $rule = $this->getDataValue($data, $rule);
+        return !is_null($rule) && strtotime($value) >= strtotime($rule);
+    }
+
+    /**
+     * 验证日期字段
+     * @access protected
+     * @param mixed     $value  字段值
+     * @param mixed     $rule  验证规则
+     * @param array     $data  数据
+     * @return bool
+     */
+    protected function beforeWith($value, $rule, $data)
+    {
+        $rule = $this->getDataValue($data, $rule);
+        return !is_null($rule) && strtotime($value) <= strtotime($rule);
+    }
+
     /**
     /**
      * 验证有效期
      * 验证有效期
      * @access protected
      * @access protected
@@ -1154,7 +1231,7 @@ class Validate
             // 不是正则表达式则两端补上/
             // 不是正则表达式则两端补上/
             $rule = '/^' . $rule . '$/';
             $rule = '/^' . $rule . '$/';
         }
         }
-        return 1 === preg_match($rule, (string) $value);
+        return is_scalar($value) && 1 === preg_match($rule, (string) $value);
     }
     }
 
 
     /**
     /**
@@ -1233,11 +1310,13 @@ class Validate
         } elseif (0 === strpos($type, 'require')) {
         } elseif (0 === strpos($type, 'require')) {
             $msg = self::$typeMsg['require'];
             $msg = self::$typeMsg['require'];
         } else {
         } else {
-            $msg = $title . '规则错误';
+            $msg = $title . Lang::get('not conform to the rules');
         }
         }
 
 
         if (is_string($msg) && 0 === strpos($msg, '{%')) {
         if (is_string($msg) && 0 === strpos($msg, '{%')) {
             $msg = Lang::get(substr($msg, 2, -1));
             $msg = Lang::get(substr($msg, 2, -1));
+        } elseif (Lang::has($msg)) {
+            $msg = Lang::get($msg);
         }
         }
 
 
         if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) {
         if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) {

+ 12 - 9
thinkphp/library/think/View.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -33,7 +33,7 @@ class View
     public function __construct($engine = [], $replace = [])
     public function __construct($engine = [], $replace = [])
     {
     {
         // 初始化模板引擎
         // 初始化模板引擎
-        $this->engine((array) $engine);
+        $this->engine($engine);
         // 基础替换字符串
         // 基础替换字符串
         $request = Request::instance();
         $request = Request::instance();
         $base    = $request->root();
         $base    = $request->root();
@@ -155,18 +155,21 @@ class View
         ob_implicit_flush(0);
         ob_implicit_flush(0);
 
 
         // 渲染输出
         // 渲染输出
-        $method = $renderContent ? 'display' : 'fetch';
-        $this->engine->$method($template, $vars, $config);
+        try {
+            $method = $renderContent ? 'display' : 'fetch';
+            // 允许用户自定义模板的字符串替换
+            $replace = array_merge($this->replace, $replace, (array) $this->engine->config('tpl_replace_string'));
+            $this->engine->config('tpl_replace_string', $replace);
+            $this->engine->$method($template, $vars, $config);
+        } catch (\Exception $e) {
+            ob_end_clean();
+            throw $e;
+        }
 
 
         // 获取并清空缓存
         // 获取并清空缓存
         $content = ob_get_clean();
         $content = ob_get_clean();
         // 内容过滤标签
         // 内容过滤标签
         Hook::listen('view_filter', $content);
         Hook::listen('view_filter', $content);
-        // 允许用户自定义模板的字符串替换
-        $replace = array_merge($this->replace, $replace);
-        if (!empty($replace)) {
-            $content = strtr($content, $replace);
-        }
         return $content;
         return $content;
     }
     }
 
 

+ 8 - 2
thinkphp/library/think/cache/Driver.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -120,8 +120,10 @@ abstract class Driver
     public function remember($name, $value, $expire = null)
     public function remember($name, $value, $expire = null)
     {
     {
         if (!$this->has($name)) {
         if (!$this->has($name)) {
-            while ($this->has($name . '_lock')) {
+            $time = time();
+            while ($time + 5 > time() && $this->has($name . '_lock')) {
                 // 存在锁定则等待
                 // 存在锁定则等待
+                usleep(200000);
             }
             }
 
 
             try {
             try {
@@ -136,6 +138,10 @@ abstract class Driver
             } catch (\Exception $e) {
             } catch (\Exception $e) {
                 // 解锁
                 // 解锁
                 $this->rm($name . '_lock');
                 $this->rm($name . '_lock');
+                throw $e;
+            } catch (\throwable $e) {
+                $this->rm($name . '_lock');
+                throw $e;
             }
             }
         } else {
         } else {
             $value = $this->get($name);
             $value = $this->get($name);

+ 34 - 16
thinkphp/library/think/cache/driver/File.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -27,6 +27,8 @@ class File extends Driver
         'data_compress' => false,
         'data_compress' => false,
     ];
     ];
 
 
+    protected $expire;
+
     /**
     /**
      * 构造函数
      * 构造函数
      * @param array $options
      * @param array $options
@@ -61,10 +63,11 @@ class File extends Driver
     /**
     /**
      * 取得变量的存储文件名
      * 取得变量的存储文件名
      * @access protected
      * @access protected
-     * @param string $name 缓存变量名
+     * @param  string $name 缓存变量名
+     * @param  bool   $auto 是否自动创建目录
      * @return string
      * @return string
      */
      */
-    protected function getCacheKey($name)
+    protected function getCacheKey($name, $auto = false)
     {
     {
         $name = md5($name);
         $name = md5($name);
         if ($this->options['cache_subdir']) {
         if ($this->options['cache_subdir']) {
@@ -76,7 +79,8 @@ class File extends Driver
         }
         }
         $filename = $this->options['path'] . $name . '.php';
         $filename = $this->options['path'] . $name . '.php';
         $dir      = dirname($filename);
         $dir      = dirname($filename);
-        if (!is_dir($dir)) {
+
+        if ($auto && !is_dir($dir)) {
             mkdir($dir, 0755, true);
             mkdir($dir, 0755, true);
         }
         }
         return $filename;
         return $filename;
@@ -106,13 +110,15 @@ class File extends Driver
         if (!is_file($filename)) {
         if (!is_file($filename)) {
             return $default;
             return $default;
         }
         }
-        $content = file_get_contents($filename);
+        $content      = file_get_contents($filename);
+        $this->expire = null;
         if (false !== $content) {
         if (false !== $content) {
             $expire = (int) substr($content, 8, 12);
             $expire = (int) substr($content, 8, 12);
-            if (0 != $expire && $_SERVER['REQUEST_TIME'] > filemtime($filename) + $expire) {
+            if (0 != $expire && time() > filemtime($filename) + $expire) {
                 return $default;
                 return $default;
             }
             }
-            $content = substr($content, 32);
+            $this->expire = $expire;
+            $content      = substr($content, 32);
             if ($this->options['data_compress'] && function_exists('gzcompress')) {
             if ($this->options['data_compress'] && function_exists('gzcompress')) {
                 //启用数据压缩
                 //启用数据压缩
                 $content = gzuncompress($content);
                 $content = gzuncompress($content);
@@ -140,7 +146,7 @@ class File extends Driver
         if ($expire instanceof \DateTime) {
         if ($expire instanceof \DateTime) {
             $expire = $expire->getTimestamp() - time();
             $expire = $expire->getTimestamp() - time();
         }
         }
-        $filename = $this->getCacheKey($name);
+        $filename = $this->getCacheKey($name, true);
         if ($this->tag && !is_file($filename)) {
         if ($this->tag && !is_file($filename)) {
             $first = true;
             $first = true;
         }
         }
@@ -170,11 +176,14 @@ class File extends Driver
     public function inc($name, $step = 1)
     public function inc($name, $step = 1)
     {
     {
         if ($this->has($name)) {
         if ($this->has($name)) {
-            $value = $this->get($name) + $step;
+            $value  = $this->get($name) + $step;
+            $expire = $this->expire;
         } else {
         } else {
-            $value = $step;
+            $value  = $step;
+            $expire = 0;
         }
         }
-        return $this->set($name, $value, 0) ? $value : false;
+
+        return $this->set($name, $value, $expire) ? $value : false;
     }
     }
 
 
     /**
     /**
@@ -187,11 +196,14 @@ class File extends Driver
     public function dec($name, $step = 1)
     public function dec($name, $step = 1)
     {
     {
         if ($this->has($name)) {
         if ($this->has($name)) {
-            $value = $this->get($name) - $step;
+            $value  = $this->get($name) - $step;
+            $expire = $this->expire;
         } else {
         } else {
-            $value = $step;
+            $value  = -$step;
+            $expire = 0;
         }
         }
-        return $this->set($name, $value, 0) ? $value : false;
+
+        return $this->set($name, $value, $expire) ? $value : false;
     }
     }
 
 
     /**
     /**
@@ -203,7 +215,10 @@ class File extends Driver
     public function rm($name)
     public function rm($name)
     {
     {
         $filename = $this->getCacheKey($name);
         $filename = $this->getCacheKey($name);
-        return $this->unlink($filename);
+        try {
+            return $this->unlink($filename);
+        } catch (\Exception $e) {
+        }
     }
     }
 
 
     /**
     /**
@@ -226,7 +241,10 @@ class File extends Driver
         $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*');
         $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*');
         foreach ($files as $path) {
         foreach ($files as $path) {
             if (is_dir($path)) {
             if (is_dir($path)) {
-                array_map('unlink', glob($path . '/*.php'));
+                $matches = glob($path . '/*.php');
+                if (is_array($matches)) {
+                    array_map('unlink', $matches);
+                }
                 rmdir($path);
                 rmdir($path);
             } else {
             } else {
                 unlink($path);
                 unlink($path);

+ 2 - 2
thinkphp/library/think/cache/driver/Lite.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -149,7 +149,7 @@ class Lite extends Driver
         if ($this->has($name)) {
         if ($this->has($name)) {
             $value = $this->get($name) - $step;
             $value = $this->get($name) - $step;
         } else {
         } else {
-            $value = $step;
+            $value = -$step;
         }
         }
         return $this->set($name, $value, 0) ? $value : false;
         return $this->set($name, $value, 0) ? $value : false;
     }
     }

+ 2 - 2
thinkphp/library/think/cache/driver/Memcache.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -63,7 +63,7 @@ class Memcache extends Driver
     public function has($name)
     public function has($name)
     {
     {
         $key = $this->getCacheKey($name);
         $key = $this->getCacheKey($name);
-        return $this->handler->get($key) ? true : false;
+        return false !== $this->handler->get($key);
     }
     }
 
 
     /**
     /**

+ 1 - 1
thinkphp/library/think/cache/driver/Memcached.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 25 - 16
thinkphp/library/think/cache/driver/Redis.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -46,9 +46,12 @@ class Redis extends Driver
         if (!empty($options)) {
         if (!empty($options)) {
             $this->options = array_merge($this->options, $options);
             $this->options = array_merge($this->options, $options);
         }
         }
-        $func          = $this->options['persistent'] ? 'pconnect' : 'connect';
         $this->handler = new \Redis;
         $this->handler = new \Redis;
-        $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);
+        if ($this->options['persistent']) {
+            $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
+        } else {
+            $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']);
+        }
 
 
         if ('' != $this->options['password']) {
         if ('' != $this->options['password']) {
             $this->handler->auth($this->options['password']);
             $this->handler->auth($this->options['password']);
@@ -67,7 +70,7 @@ class Redis extends Driver
      */
      */
     public function has($name)
     public function has($name)
     {
     {
-        return $this->handler->get($this->getCacheKey($name)) ? true : false;
+        return $this->handler->exists($this->getCacheKey($name));
     }
     }
 
 
     /**
     /**
@@ -80,12 +83,17 @@ class Redis extends Driver
     public function get($name, $default = false)
     public function get($name, $default = false)
     {
     {
         $value = $this->handler->get($this->getCacheKey($name));
         $value = $this->handler->get($this->getCacheKey($name));
-        if (is_null($value)) {
+        if (is_null($value) || false === $value) {
             return $default;
             return $default;
         }
         }
-        $jsonData = json_decode($value, true);
-        // 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson<xiaobo.sun@qq.com>
-        return (null === $jsonData) ? $value : $jsonData;
+
+        try {
+            $result = 0 === strpos($value, 'think_serialize:') ? unserialize(substr($value, 16)) : $value;
+        } catch (\Exception $e) {
+            $result = $default;
+        }
+
+        return $result;
     }
     }
 
 
     /**
     /**
@@ -107,10 +115,9 @@ class Redis extends Driver
         if ($this->tag && !$this->has($name)) {
         if ($this->tag && !$this->has($name)) {
             $first = true;
             $first = true;
         }
         }
-        $key = $this->getCacheKey($name);
-        //对数组/对象数据进行缓存处理,保证数据完整性  byron sampson<xiaobo.sun@qq.com>
-        $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
-        if (is_int($expire) && $expire) {
+        $key   = $this->getCacheKey($name);
+        $value = is_scalar($value) ? $value : 'think_serialize:' . serialize($value);
+        if ($expire) {
             $result = $this->handler->setex($key, $expire, $value);
             $result = $this->handler->setex($key, $expire, $value);
         } else {
         } else {
             $result = $this->handler->set($key, $value);
             $result = $this->handler->set($key, $value);
@@ -122,26 +129,28 @@ class Redis extends Driver
     /**
     /**
      * 自增缓存(针对数值缓存)
      * 自增缓存(针对数值缓存)
      * @access public
      * @access public
-     * @param string    $name 缓存变量名
-     * @param int       $step 步长
+     * @param  string    $name 缓存变量名
+     * @param  int       $step 步长
      * @return false|int
      * @return false|int
      */
      */
     public function inc($name, $step = 1)
     public function inc($name, $step = 1)
     {
     {
         $key = $this->getCacheKey($name);
         $key = $this->getCacheKey($name);
+
         return $this->handler->incrby($key, $step);
         return $this->handler->incrby($key, $step);
     }
     }
 
 
     /**
     /**
      * 自减缓存(针对数值缓存)
      * 自减缓存(针对数值缓存)
      * @access public
      * @access public
-     * @param string    $name 缓存变量名
-     * @param int       $step 步长
+     * @param  string    $name 缓存变量名
+     * @param  int       $step 步长
      * @return false|int
      * @return false|int
      */
      */
     public function dec($name, $step = 1)
     public function dec($name, $step = 1)
     {
     {
         $key = $this->getCacheKey($name);
         $key = $this->getCacheKey($name);
+
         return $this->handler->decrby($key, $step);
         return $this->handler->decrby($key, $step);
     }
     }
 
 

+ 2 - 2
thinkphp/library/think/cache/driver/Sqlite.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -159,7 +159,7 @@ class Sqlite extends Driver
         if ($this->has($name)) {
         if ($this->has($name)) {
             $value = $this->get($name) - $step;
             $value = $this->get($name) - $step;
         } else {
         } else {
-            $value = $step;
+            $value = -$step;
         }
         }
         return $this->set($name, $value, 0) ? $value : false;
         return $this->set($name, $value, 0) ? $value : false;
     }
     }

+ 1 - 1
thinkphp/library/think/cache/driver/Wincache.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/cache/driver/Xcache.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/config/driver/Ini.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/config/driver/Json.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/config/driver/Xml.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 11 - 2
thinkphp/library/think/console/command/Clear.php

@@ -10,8 +10,10 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 namespace think\console\command;
 namespace think\console\command;
 
 
+use think\Cache;
 use think\console\Command;
 use think\console\Command;
 use think\console\Input;
 use think\console\Input;
+use think\console\input\Argument;
 use think\console\input\Option;
 use think\console\input\Option;
 use think\console\Output;
 use think\console\Output;
 
 
@@ -22,6 +24,7 @@ class Clear extends Command
         // 指令配置
         // 指令配置
         $this
         $this
             ->setName('clear')
             ->setName('clear')
+            ->addArgument('type', Argument::OPTIONAL, 'type to clear', null)
             ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)
             ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)
             ->setDescription('Clear runtime file');
             ->setDescription('Clear runtime file');
     }
     }
@@ -30,8 +33,14 @@ class Clear extends Command
     {
     {
         $path = $input->getOption('path') ?: RUNTIME_PATH;
         $path = $input->getOption('path') ?: RUNTIME_PATH;
 
 
-        if (is_dir($path)) {
-            $this->clearPath($path);
+        $type = $input->getArgument('type');
+
+        if ($type == 'route') {
+            Cache::clear('route_check');
+        } else {
+            if (is_dir($path)) {
+                $this->clearPath($path);
+            }
         }
         }
 
 
         $output->writeln("<info>Clear Successed</info>");
         $output->writeln("<info>Clear Successed</info>");

+ 1 - 1
thinkphp/library/think/console/command/optimize/Config.php

@@ -30,7 +30,7 @@ class Config extends Command
 
 
     protected function execute(Input $input, Output $output)
     protected function execute(Input $input, Output $output)
     {
     {
-        if ($input->hasArgument('module')) {
+        if ($input->getArgument('module')) {
             $module = $input->getArgument('module') . DS;
             $module = $input->getArgument('module') . DS;
         } else {
         } else {
             $module = '';
             $module = '';

+ 5 - 0
thinkphp/library/think/console/command/optimize/Route.php

@@ -27,6 +27,11 @@ class Route extends Command
 
 
     protected function execute(Input $input, Output $output)
     protected function execute(Input $input, Output $output)
     {
     {
+
+        if (!is_dir(RUNTIME_PATH)) {
+            @mkdir(RUNTIME_PATH, 0755, true);
+        }
+
         file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache());
         file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache());
         $output->writeln('<info>Succeed!</info>');
         $output->writeln('<info>Succeed!</info>');
     }
     }

+ 4 - 2
thinkphp/library/think/console/command/optimize/Schema.php

@@ -44,7 +44,8 @@ class Schema extends Command
         if ($input->hasOption('module')) {
         if ($input->hasOption('module')) {
             $module = $input->getOption('module');
             $module = $input->getOption('module');
             // 读取模型
             // 读取模型
-            $list = scandir(APP_PATH . $module . DS . 'model');
+            $path = APP_PATH . $module . DS . 'model';
+            $list = is_dir($path) ? scandir($path) : [];
             $app  = App::$namespace;
             $app  = App::$namespace;
             foreach ($list as $file) {
             foreach ($list as $file) {
                 if (0 === strpos($file, '.')) {
                 if (0 === strpos($file, '.')) {
@@ -66,7 +67,8 @@ class Schema extends Command
             $tables = Db::connect($config)->getTables($dbName);
             $tables = Db::connect($config)->getTables($dbName);
         } elseif (!\think\Config::get('app_multi_module')) {
         } elseif (!\think\Config::get('app_multi_module')) {
             $app  = App::$namespace;
             $app  = App::$namespace;
-            $list = scandir(APP_PATH . 'model');
+            $path = APP_PATH . 'model';
+            $list = is_dir($path) ? scandir($path) : [];
             foreach ($list as $file) {
             foreach ($list as $file) {
                 if (0 === strpos($file, '.')) {
                 if (0 === strpos($file, '.')) {
                     continue;
                     continue;

+ 3 - 3
thinkphp/library/think/controller/Rest.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -43,7 +43,7 @@ abstract class Rest
         if ('' == $ext) {
         if ('' == $ext) {
             // 自动检测资源类型
             // 自动检测资源类型
             $this->type = $request->type();
             $this->type = $request->type();
-        } elseif (!preg_match('/\(' . $this->restTypeList . '\)$/i', $ext)) {
+        } elseif (!preg_match('/(' . $this->restTypeList . ')$/i', $ext)) {
             // 资源类型非法 则用默认资源类型访问
             // 资源类型非法 则用默认资源类型访问
             $this->type = $this->restDefaultType;
             $this->type = $this->restDefaultType;
         } else {
         } else {
@@ -51,7 +51,7 @@ abstract class Rest
         }
         }
         // 请求方式检测
         // 请求方式检测
         $method = strtolower($request->method());
         $method = strtolower($request->method());
-        if (false === stripos($this->restMethodList, $method)) {
+        if (!preg_match('/(' . $this->restMethodList . ')$/i', $method)) {
             // 请求方式非法 则用默认请求方法
             // 请求方式非法 则用默认请求方法
             $method = $this->restDefaultMethod;
             $method = $this->restDefaultMethod;
         }
         }

+ 85 - 50
thinkphp/library/think/db/Builder.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -11,7 +11,6 @@
 
 
 namespace think\db;
 namespace think\db;
 
 
-use BadMethodCallException;
 use PDO;
 use PDO;
 use think\Exception;
 use think\Exception;
 
 
@@ -26,7 +25,7 @@ abstract class Builder
     protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'];
     protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'];
 
 
     // SQL表达式
     // SQL表达式
-    protected $selectSql    = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
+    protected $selectSql    = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%%LOCK%%COMMENT%';
     protected $insertSql    = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
     protected $insertSql    = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
     protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
     protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
     protected $updateSql    = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
     protected $updateSql    = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
@@ -99,8 +98,15 @@ abstract class Builder
 
 
         $result = [];
         $result = [];
         foreach ($data as $key => $val) {
         foreach ($data as $key => $val) {
-            $item = $this->parseKey($key, $options);
-            if (is_object($val) && method_exists($val, '__toString')) {
+            if ('*' != $options['field'] && !in_array($key, $fields, true)) {
+                continue;
+            }
+
+            $item = $this->parseKey($key, $options, true);
+            if ($val instanceof Expression) {
+                $result[$item] = $val->getValue();
+                continue;
+            } elseif (is_object($val) && method_exists($val, '__toString')) {
                 // 对象数据写入
                 // 对象数据写入
                 $val = $val->__toString();
                 $val = $val->__toString();
             }
             }
@@ -110,8 +116,17 @@ abstract class Builder
                 }
                 }
             } elseif (is_null($val)) {
             } elseif (is_null($val)) {
                 $result[$item] = 'NULL';
                 $result[$item] = 'NULL';
-            } elseif (isset($val[0]) && 'exp' == $val[0]) {
-                $result[$item] = $val[1];
+            } elseif (is_array($val) && !empty($val)) {
+                switch (strtolower($val[0])) {
+                    case 'inc':
+                        $result[$item] = $item . '+' . floatval($val[1]);
+                        break;
+                    case 'dec':
+                        $result[$item] = $item . '-' . floatval($val[1]);
+                        break;
+                    case 'exp':
+                        throw new Exception('not support data:[' . $val[0] . ']');
+                }
             } elseif (is_scalar($val)) {
             } elseif (is_scalar($val)) {
                 // 过滤非标量数据
                 // 过滤非标量数据
                 if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {
                 if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {
@@ -133,7 +148,7 @@ abstract class Builder
      * @param array  $options
      * @param array  $options
      * @return string
      * @return string
      */
      */
-    protected function parseKey($key, $options = [])
+    protected function parseKey($key, $options = [], $strict = false)
     {
     {
         return $key;
         return $key;
     }
     }
@@ -174,8 +189,10 @@ abstract class Builder
             // 支持 'field1'=>'field2' 这样的字段别名定义
             // 支持 'field1'=>'field2' 这样的字段别名定义
             $array = [];
             $array = [];
             foreach ($fields as $key => $field) {
             foreach ($fields as $key => $field) {
-                if (!is_numeric($key)) {
-                    $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options);
+                if ($field instanceof Expression) {
+                    $array[] = $field->getValue();
+                } elseif (!is_numeric($key)) {
+                    $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options, true);
                 } else {
                 } else {
                     $array[] = $this->parseKey($field, $options);
                     $array[] = $this->parseKey($field, $options);
                 }
                 }
@@ -197,9 +214,6 @@ abstract class Builder
         $item = [];
         $item = [];
         foreach ((array) $tables as $key => $table) {
         foreach ((array) $tables as $key => $table) {
             if (!is_numeric($key)) {
             if (!is_numeric($key)) {
-                if (strpos($key, '@think')) {
-                    $key = strstr($key, '@think', true);
-                }
                 $key    = $this->parseSqlTable($key);
                 $key    = $this->parseSqlTable($key);
                 $item[] = $this->parseKey($key) . ' ' . (isset($options['alias'][$table]) ? $this->parseKey($options['alias'][$table]) : $this->parseKey($table));
                 $item[] = $this->parseKey($key) . ' ' . (isset($options['alias'][$table]) ? $this->parseKey($options['alias'][$table]) : $this->parseKey($table));
             } else {
             } else {
@@ -257,7 +271,9 @@ abstract class Builder
         foreach ($where as $key => $val) {
         foreach ($where as $key => $val) {
             $str = [];
             $str = [];
             foreach ($val as $field => $value) {
             foreach ($val as $field => $value) {
-                if ($value instanceof \Closure) {
+                if ($value instanceof Expression) {
+                    $str[] = ' ' . $key . ' ( ' . $value->getValue() . ' )';
+                } elseif ($value instanceof \Closure) {
                     // 使用闭包查询
                     // 使用闭包查询
                     $query = new Query($this->connection);
                     $query = new Query($this->connection);
                     call_user_func_array($value, [ & $query]);
                     call_user_func_array($value, [ & $query]);
@@ -298,7 +314,7 @@ abstract class Builder
     protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)
     protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)
     {
     {
         // 字段分析
         // 字段分析
-        $key = $field ? $this->parseKey($field, $options) : '';
+        $key = $field ? $this->parseKey($field, $options, true) : '';
 
 
         // 查询规则和条件
         // 查询规则和条件
         if (!is_array($val)) {
         if (!is_array($val)) {
@@ -331,13 +347,15 @@ abstract class Builder
                 throw new Exception('where express error:' . $exp);
                 throw new Exception('where express error:' . $exp);
             }
             }
         }
         }
-        $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);
+        $bindName = $bindName ?: 'where_' . $rule . '_' . str_replace(['.', '-'], '_', $field);
         if (preg_match('/\W/', $bindName)) {
         if (preg_match('/\W/', $bindName)) {
             // 处理带非单词字符的字段名
             // 处理带非单词字符的字段名
             $bindName = md5($bindName);
             $bindName = md5($bindName);
         }
         }
 
 
-        if (is_object($value) && method_exists($value, '__toString')) {
+        if ($value instanceof Expression) {
+
+        } elseif (is_object($value) && method_exists($value, '__toString')) {
             // 对象数据写入
             // 对象数据写入
             $value = $value->__toString();
             $value = $value->__toString();
         }
         }
@@ -374,7 +392,11 @@ abstract class Builder
             }
             }
         } elseif ('EXP' == $exp) {
         } elseif ('EXP' == $exp) {
             // 表达式查询
             // 表达式查询
-            $whereStr .= '( ' . $key . ' ' . $value . ' )';
+            if ($value instanceof Expression) {
+                $whereStr .= '( ' . $key . ' ' . $value->getValue() . ' )';
+            } else {
+                throw new Exception('where express error:' . $exp);
+            }
         } elseif (in_array($exp, ['NOT NULL', 'NULL'])) {
         } elseif (in_array($exp, ['NOT NULL', 'NULL'])) {
             // NULL 查询
             // NULL 查询
             $whereStr .= $key . ' IS ' . $exp;
             $whereStr .= $key . ' IS ' . $exp;
@@ -492,6 +514,11 @@ abstract class Builder
             }
             }
         }
         }
         $bindName = $bindName ?: $key;
         $bindName = $bindName ?: $key;
+
+        if ($this->query->isBind($bindName)) {
+            $bindName .= '_' . str_replace('.', '_', uniqid('', true));
+        }
+
         $this->query->bind($bindName, $value, $bindType);
         $this->query->bind($bindName, $value, $bindType);
         return ':' . $bindName;
         return ':' . $bindName;
     }
     }
@@ -522,7 +549,9 @@ abstract class Builder
                 list($table, $type, $on) = $item;
                 list($table, $type, $on) = $item;
                 $condition               = [];
                 $condition               = [];
                 foreach ((array) $on as $val) {
                 foreach ((array) $on as $val) {
-                    if (strpos($val, '=')) {
+                    if ($val instanceof Expression) {
+                        $condition[] = $val->getValue();
+                    } elseif (strpos($val, '=')) {
                         list($val1, $val2) = explode('=', $val, 2);
                         list($val1, $val2) = explode('=', $val, 2);
                         $condition[]       = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options);
                         $condition[]       = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options);
                     } else {
                     } else {
@@ -546,28 +575,29 @@ abstract class Builder
      */
      */
     protected function parseOrder($order, $options = [])
     protected function parseOrder($order, $options = [])
     {
     {
-        if (is_array($order)) {
-            $array = [];
-            foreach ($order as $key => $val) {
+        if (empty($order)) {
+            return '';
+        }
+
+        $array = [];
+        foreach ($order as $key => $val) {
+            if ($val instanceof Expression) {
+                $array[] = $val->getValue();
+            } elseif ('[rand]' == $val) {
+                $array[] = $this->parseRand();
+            } else {
                 if (is_numeric($key)) {
                 if (is_numeric($key)) {
-                    if ('[rand]' == $val) {
-                        if (method_exists($this, 'parseRand')) {
-                            $array[] = $this->parseRand();
-                        } else {
-                            throw new BadMethodCallException('method not exists:' . get_class($this) . '-> parseRand');
-                        }
-                    } elseif (false === strpos($val, '(')) {
-                        $array[] = $this->parseKey($val, $options);
-                    } else {
-                        $array[] = $val;
-                    }
+                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
                 } else {
                 } else {
-                    $sort    = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';
-                    $array[] = $this->parseKey($key, $options) . ' ' . $sort;
+                    $sort = $val;
                 }
                 }
+                $sort    = strtoupper($sort);
+                $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
+                $array[] = $this->parseKey($key, $options, true) . $sort;
             }
             }
-            $order = implode(',', $array);
         }
         }
+        $order = implode(',', $array);
+
         return !empty($order) ? ' ORDER BY ' . $order : '';
         return !empty($order) ? ' ORDER BY ' . $order : '';
     }
     }
 
 
@@ -601,6 +631,9 @@ abstract class Builder
      */
      */
     protected function parseComment($comment)
     protected function parseComment($comment)
     {
     {
+        if (false !== strpos($comment, '*/')) {
+            $comment = strstr($comment, '*/', true);
+        }
         return !empty($comment) ? ' /* ' . $comment . ' */' : '';
         return !empty($comment) ? ' /* ' . $comment . ' */' : '';
     }
     }
 
 
@@ -630,12 +663,12 @@ abstract class Builder
         unset($union['type']);
         unset($union['type']);
         foreach ($union as $u) {
         foreach ($union as $u) {
             if ($u instanceof \Closure) {
             if ($u instanceof \Closure) {
-                $sql[] = $type . ' ' . $this->parseClosure($u, false);
+                $sql[] = $type . ' ' . $this->parseClosure($u);
             } elseif (is_string($u)) {
             } elseif (is_string($u)) {
-                $sql[] = $type . ' ' . $this->parseSqlTable($u);
+                $sql[] = $type . ' ( ' . $this->parseSqlTable($u) . ' )';
             }
             }
         }
         }
-        return implode(' ', $sql);
+        return ' ' . implode(' ', $sql);
     }
     }
 
 
     /**
     /**
@@ -650,11 +683,7 @@ abstract class Builder
             return '';
             return '';
         }
         }
 
 
-        if (is_array($index)) {
-            $index = join(",", $index);
-        }
-
-        return sprintf(" FORCE INDEX ( %s ) ", $index);
+        return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index);
     }
     }
 
 
     /**
     /**
@@ -749,7 +778,7 @@ abstract class Builder
             $fields = $options['field'];
             $fields = $options['field'];
         }
         }
 
 
-        foreach ($dataSet as &$data) {
+        foreach ($dataSet as $data) {
             foreach ($data as $key => $val) {
             foreach ($data as $key => $val) {
                 if (!in_array($key, $fields, true)) {
                 if (!in_array($key, $fields, true)) {
                     if ($options['strict']) {
                     if ($options['strict']) {
@@ -770,19 +799,25 @@ abstract class Builder
             }
             }
             $value    = array_values($data);
             $value    = array_values($data);
             $values[] = 'SELECT ' . implode(',', $value);
             $values[] = 'SELECT ' . implode(',', $value);
+
+            if (!isset($insertFields)) {
+                $insertFields = array_keys($data);
+            }
+        }
+
+        foreach ($insertFields as $field) {
+            $fields[] = $this->parseKey($field, $options, true);
         }
         }
-        $fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
-        $sql    = str_replace(
+
+        return str_replace(
             ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
             ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
             [
             [
                 $replace ? 'REPLACE' : 'INSERT',
                 $replace ? 'REPLACE' : 'INSERT',
                 $this->parseTable($options['table'], $options),
                 $this->parseTable($options['table'], $options),
-                implode(' , ', $fields),
+                implode(' , ', $insertFields),
                 implode(' UNION ALL ', $values),
                 implode(' UNION ALL ', $values),
                 $this->parseComment($options['comment']),
                 $this->parseComment($options['comment']),
             ], $this->insertAllSql);
             ], $this->insertAllSql);
-
-        return $sql;
     }
     }
 
 
     /**
     /**

+ 62 - 36
thinkphp/library/think/db/Connection.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -90,6 +90,8 @@ abstract class Connection
         'master_num'      => 1,
         'master_num'      => 1,
         // 指定从服务器序号
         // 指定从服务器序号
         'slave_no'        => '',
         'slave_no'        => '',
+        // 模型写入后自动读取主服务器
+        'read_master'     => false,
         // 是否严格检查字段是否存在
         // 是否严格检查字段是否存在
         'fields_strict'   => true,
         'fields_strict'   => true,
         // 数据返回类型
         // 数据返回类型
@@ -354,19 +356,14 @@ abstract class Connection
             $this->bind = $bind;
             $this->bind = $bind;
         }
         }
 
 
-        // 释放前次的查询结果
-        if (!empty($this->PDOStatement)) {
-            $this->free();
-        }
-
         Db::$queryTimes++;
         Db::$queryTimes++;
         try {
         try {
             // 调试开始
             // 调试开始
             $this->debug(true);
             $this->debug(true);
+
             // 预处理
             // 预处理
-            if (empty($this->PDOStatement)) {
-                $this->PDOStatement = $this->linkID->prepare($sql);
-            }
+            $this->PDOStatement = $this->linkID->prepare($sql);
+
             // 是否为存储过程调用
             // 是否为存储过程调用
             $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
             $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
             // 参数绑定
             // 参数绑定
@@ -378,7 +375,7 @@ abstract class Connection
             // 执行查询
             // 执行查询
             $this->PDOStatement->execute();
             $this->PDOStatement->execute();
             // 调试结束
             // 调试结束
-            $this->debug(false);
+            $this->debug(false, '', $master);
             // 返回结果集
             // 返回结果集
             return $this->getResult($pdo, $procedure);
             return $this->getResult($pdo, $procedure);
         } catch (\PDOException $e) {
         } catch (\PDOException $e) {
@@ -386,6 +383,11 @@ abstract class Connection
                 return $this->close()->query($sql, $bind, $master, $pdo);
                 return $this->close()->query($sql, $bind, $master, $pdo);
             }
             }
             throw new PDOException($e, $this->config, $this->getLastsql());
             throw new PDOException($e, $this->config, $this->getLastsql());
+        } catch (\Throwable $e) {
+            if ($this->isBreak($e)) {
+                return $this->close()->query($sql, $bind, $master, $pdo);
+            }
+            throw $e;
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             if ($this->isBreak($e)) {
             if ($this->isBreak($e)) {
                 return $this->close()->query($sql, $bind, $master, $pdo);
                 return $this->close()->query($sql, $bind, $master, $pdo);
@@ -397,13 +399,14 @@ abstract class Connection
     /**
     /**
      * 执行语句
      * 执行语句
      * @access public
      * @access public
-     * @param string        $sql sql指令
-     * @param array         $bind 参数绑定
+     * @param  string        $sql sql指令
+     * @param  array         $bind 参数绑定
+     * @param  Query         $query 查询对象
      * @return int
      * @return int
      * @throws PDOException
      * @throws PDOException
      * @throws \Exception
      * @throws \Exception
      */
      */
-    public function execute($sql, $bind = [])
+    public function execute($sql, $bind = [], Query $query = null)
     {
     {
         $this->initConnect(true);
         $this->initConnect(true);
         if (!$this->linkID) {
         if (!$this->linkID) {
@@ -416,19 +419,14 @@ abstract class Connection
             $this->bind = $bind;
             $this->bind = $bind;
         }
         }
 
 
-        //释放前次的查询结果
-        if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {
-            $this->free();
-        }
-
         Db::$executeTimes++;
         Db::$executeTimes++;
         try {
         try {
             // 调试开始
             // 调试开始
             $this->debug(true);
             $this->debug(true);
+
             // 预处理
             // 预处理
-            if (empty($this->PDOStatement)) {
-                $this->PDOStatement = $this->linkID->prepare($sql);
-            }
+            $this->PDOStatement = $this->linkID->prepare($sql);
+
             // 是否为存储过程调用
             // 是否为存储过程调用
             $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
             $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
             // 参数绑定
             // 参数绑定
@@ -440,18 +438,27 @@ abstract class Connection
             // 执行语句
             // 执行语句
             $this->PDOStatement->execute();
             $this->PDOStatement->execute();
             // 调试结束
             // 调试结束
-            $this->debug(false);
+            $this->debug(false, '', true);
+
+            if ($query && !empty($this->config['deploy']) && !empty($this->config['read_master'])) {
+                $query->readMaster();
+            }
 
 
             $this->numRows = $this->PDOStatement->rowCount();
             $this->numRows = $this->PDOStatement->rowCount();
             return $this->numRows;
             return $this->numRows;
         } catch (\PDOException $e) {
         } catch (\PDOException $e) {
             if ($this->isBreak($e)) {
             if ($this->isBreak($e)) {
-                return $this->close()->execute($sql, $bind);
+                return $this->close()->execute($sql, $bind, $query);
             }
             }
             throw new PDOException($e, $this->config, $this->getLastsql());
             throw new PDOException($e, $this->config, $this->getLastsql());
+        } catch (\Throwable $e) {
+            if ($this->isBreak($e)) {
+                return $this->close()->execute($sql, $bind, $query);
+            }
+            throw $e;
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             if ($this->isBreak($e)) {
             if ($this->isBreak($e)) {
-                return $this->close()->execute($sql, $bind);
+                return $this->close()->execute($sql, $bind, $query);
             }
             }
             throw $e;
             throw $e;
         }
         }
@@ -466,6 +473,10 @@ abstract class Connection
      */
      */
     public function getRealSql($sql, array $bind = [])
     public function getRealSql($sql, array $bind = [])
     {
     {
+        if (is_array($sql)) {
+            $sql = implode(';', $sql);
+        }
+
         foreach ($bind as $key => $val) {
         foreach ($bind as $key => $val) {
             $value = is_array($val) ? $val[0] : $val;
             $value = is_array($val) ? $val[0] : $val;
             $type  = is_array($val) ? $val[1] : PDO::PARAM_STR;
             $type  = is_array($val) ? $val[1] : PDO::PARAM_STR;
@@ -478,8 +489,8 @@ abstract class Connection
             $sql = is_numeric($key) ?
             $sql = is_numeric($key) ?
             substr_replace($sql, $value, strpos($sql, '?'), 1) :
             substr_replace($sql, $value, strpos($sql, '?'), 1) :
             str_replace(
             str_replace(
-                [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '],
-                [$value . ')', $value . ',', $value . ' '],
+                [':' . $key . ')', ':' . $key . ',', ':' . $key . ' ', ':' . $key . PHP_EOL],
+                [$value . ')', $value . ',', $value . ' ', $value . PHP_EOL],
                 $sql . ' ');
                 $sql . ' ');
         }
         }
         return rtrim($sql);
         return rtrim($sql);
@@ -638,13 +649,15 @@ abstract class Connection
                 );
                 );
             }
             }
 
 
-        } catch (\PDOException $e) {
+        } catch (\Exception $e) {
             if ($this->isBreak($e)) {
             if ($this->isBreak($e)) {
+                --$this->transTimes;
                 return $this->close()->startTrans();
                 return $this->close()->startTrans();
             }
             }
             throw $e;
             throw $e;
-        } catch (\Exception $e) {
+        } catch (\Error $e) {
             if ($this->isBreak($e)) {
             if ($this->isBreak($e)) {
+                --$this->transTimes;
                 return $this->close()->startTrans();
                 return $this->close()->startTrans();
             }
             }
             throw $e;
             throw $e;
@@ -725,7 +738,7 @@ abstract class Connection
      * @param array $sqlArray SQL批处理指令
      * @param array $sqlArray SQL批处理指令
      * @return boolean
      * @return boolean
      */
      */
-    public function batchQuery($sqlArray = [])
+    public function batchQuery($sqlArray = [], $bind = [], Query $query = null)
     {
     {
         if (!is_array($sqlArray)) {
         if (!is_array($sqlArray)) {
             return false;
             return false;
@@ -734,7 +747,7 @@ abstract class Connection
         $this->startTrans();
         $this->startTrans();
         try {
         try {
             foreach ($sqlArray as $sql) {
             foreach ($sqlArray as $sql) {
-                $this->execute($sql);
+                $this->execute($sql, $bind, $query);
             }
             }
             // 提交事务
             // 提交事务
             $this->commit();
             $this->commit();
@@ -742,6 +755,7 @@ abstract class Connection
             $this->rollback();
             $this->rollback();
             throw $e;
             throw $e;
         }
         }
+
         return true;
         return true;
     }
     }
 
 
@@ -777,6 +791,8 @@ abstract class Connection
         $this->linkWrite = null;
         $this->linkWrite = null;
         $this->linkRead  = null;
         $this->linkRead  = null;
         $this->links     = [];
         $this->links     = [];
+        // 释放查询
+        $this->free();
         return $this;
         return $this;
     }
     }
 
 
@@ -803,6 +819,7 @@ abstract class Connection
             'SSL connection has been closed unexpectedly',
             'SSL connection has been closed unexpectedly',
             'Error writing data to the connection',
             'Error writing data to the connection',
             'Resource deadlock avoided',
             'Resource deadlock avoided',
+            'failed with errno',
         ];
         ];
 
 
         $error = $e->getMessage();
         $error = $e->getMessage();
@@ -883,9 +900,10 @@ abstract class Connection
      * @access protected
      * @access protected
      * @param boolean $start 调试开始标记 true 开始 false 结束
      * @param boolean $start 调试开始标记 true 开始 false 结束
      * @param string  $sql 执行的SQL语句 留空自动获取
      * @param string  $sql 执行的SQL语句 留空自动获取
+     * @param boolean $master 主从标记
      * @return void
      * @return void
      */
      */
-    protected function debug($start, $sql = '')
+    protected function debug($start, $sql = '', $master = false)
     {
     {
         if (!empty($this->config['debug'])) {
         if (!empty($this->config['debug'])) {
             // 开启数据库调试模式
             // 开启数据库调试模式
@@ -902,7 +920,7 @@ abstract class Connection
                     $result = $this->getExplain($sql);
                     $result = $this->getExplain($sql);
                 }
                 }
                 // SQL监听
                 // SQL监听
-                $this->trigger($sql, $runtime, $result);
+                $this->trigger($sql, $runtime, $result, $master);
             }
             }
         }
         }
     }
     }
@@ -924,19 +942,27 @@ abstract class Connection
      * @param string    $sql SQL语句
      * @param string    $sql SQL语句
      * @param float     $runtime SQL运行时间
      * @param float     $runtime SQL运行时间
      * @param mixed     $explain SQL分析
      * @param mixed     $explain SQL分析
-     * @return bool
+     * @param  bool     $master 主从标记
+     * @return void
      */
      */
-    protected function trigger($sql, $runtime, $explain = [])
+    protected function trigger($sql, $runtime, $explain = [], $master = false)
     {
     {
         if (!empty(self::$event)) {
         if (!empty(self::$event)) {
             foreach (self::$event as $callback) {
             foreach (self::$event as $callback) {
                 if (is_callable($callback)) {
                 if (is_callable($callback)) {
-                    call_user_func_array($callback, [$sql, $runtime, $explain]);
+                    call_user_func_array($callback, [$sql, $runtime, $explain, $master]);
                 }
                 }
             }
             }
         } else {
         } else {
             // 未注册监听则记录到日志中
             // 未注册监听则记录到日志中
-            Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql');
+            if ($this->config['deploy']) {
+                // 分布式记录当前操作的主从
+                $master = $master ? 'master|' : 'slave|';
+            } else {
+                $master = '';
+            }
+
+            Log::record('[ SQL ] ' . $sql . ' [ ' . $master . 'RunTime:' . $runtime . 's ]', 'sql');
             if (!empty($explain)) {
             if (!empty($explain)) {
                 Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql');
                 Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql');
             }
             }

+ 48 - 0
thinkphp/library/think/db/Expression.php

@@ -0,0 +1,48 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+namespace think\db;
+
+class Expression
+{
+    /**
+     * 查询表达式
+     *
+     * @var string
+     */
+    protected $value;
+
+    /**
+     * 创建一个查询表达式
+     *
+     * @param  string  $value
+     * @return void
+     */
+    public function __construct($value)
+    {
+        $this->value = $value;
+    }
+
+    /**
+     * 获取表达式
+     *
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    public function __toString()
+    {
+        return (string) $this->value;
+    }
+}

File diff suppressed because it is too large
+ 379 - 165
thinkphp/library/think/db/Query.php


+ 75 - 6
thinkphp/library/think/db/builder/Mysql.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -12,28 +12,93 @@
 namespace think\db\builder;
 namespace think\db\builder;
 
 
 use think\db\Builder;
 use think\db\Builder;
+use think\Exception;
 
 
 /**
 /**
  * mysql数据库驱动
  * mysql数据库驱动
  */
  */
 class Mysql extends Builder
 class Mysql extends Builder
 {
 {
-    protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
+
+    protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%';
+    protected $updateSql    = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
+
+    /**
+     * 生成insertall SQL
+     * @access public
+     * @param array     $dataSet 数据集
+     * @param array     $options 表达式
+     * @param bool      $replace 是否replace
+     * @return string
+     * @throws Exception
+     */
+    public function insertAll($dataSet, $options = [], $replace = false)
+    {
+        // 获取合法的字段
+        if ('*' == $options['field']) {
+            $fields = array_keys($this->query->getFieldsType($options['table']));
+        } else {
+            $fields = $options['field'];
+        }
+
+        foreach ($dataSet as $data) {
+            foreach ($data as $key => $val) {
+                if (!in_array($key, $fields, true)) {
+                    if ($options['strict']) {
+                        throw new Exception('fields not exists:[' . $key . ']');
+                    }
+                    unset($data[$key]);
+                } elseif (is_null($val)) {
+                    $data[$key] = 'NULL';
+                } elseif (is_scalar($val)) {
+                    $data[$key] = $this->parseValue($val, $key);
+                } elseif (is_object($val) && method_exists($val, '__toString')) {
+                    // 对象数据写入
+                    $data[$key] = $val->__toString();
+                } else {
+                    // 过滤掉非标量数据
+                    unset($data[$key]);
+                }
+            }
+            $value    = array_values($data);
+            $values[] = '( ' . implode(',', $value) . ' )';
+
+            if (!isset($insertFields)) {
+                $insertFields = array_map([$this, 'parseKey'], array_keys($data));
+            }
+        }
+
+        return str_replace(
+            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
+            [
+                $replace ? 'REPLACE' : 'INSERT',
+                $this->parseTable($options['table'], $options),
+                implode(' , ', $insertFields),
+                implode(' , ', $values),
+                $this->parseComment($options['comment']),
+            ], $this->insertAllSql);
+    }
 
 
     /**
     /**
      * 字段和表名处理
      * 字段和表名处理
      * @access protected
      * @access protected
-     * @param string $key
+     * @param mixed  $key
      * @param array  $options
      * @param array  $options
      * @return string
      * @return string
      */
      */
-    protected function parseKey($key, $options = [])
+    protected function parseKey($key, $options = [], $strict = false)
     {
     {
+        if (is_numeric($key)) {
+            return $key;
+        } elseif ($key instanceof Expression) {
+            return $key->getValue();
+        }
+
         $key = trim($key);
         $key = trim($key);
         if (strpos($key, '$.') && false === strpos($key, '(')) {
         if (strpos($key, '$.') && false === strpos($key, '(')) {
             // JSON字段支持
             // JSON字段支持
             list($field, $name) = explode('$.', $key);
             list($field, $name) = explode('$.', $key);
-            $key                = 'json_extract(' . $field . ', \'$.' . $name . '\')';
+            return 'json_extract(' . $field . ', \'$.' . $name . '\')';
         } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
         } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
             list($table, $key) = explode('.', $key, 2);
             list($table, $key) = explode('.', $key, 2);
             if ('__TABLE__' == $table) {
             if ('__TABLE__' == $table) {
@@ -43,7 +108,11 @@ class Mysql extends Builder
                 $table = $options['alias'][$table];
                 $table = $options['alias'][$table];
             }
             }
         }
         }
-        if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
+
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
+            throw new Exception('not support data:' . $key);
+        }
+        if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) {
             $key = '`' . $key . '`';
             $key = '`' . $key . '`';
         }
         }
         if (isset($table)) {
         if (isset($table)) {

+ 9 - 3
thinkphp/library/think/db/builder/Pgsql.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -44,12 +44,18 @@ class Pgsql extends Builder
     /**
     /**
      * 字段和表名处理
      * 字段和表名处理
      * @access protected
      * @access protected
-     * @param string $key
+     * @param mixed  $key
      * @param array  $options
      * @param array  $options
      * @return string
      * @return string
      */
      */
-    protected function parseKey($key, $options = [])
+    protected function parseKey($key, $options = [], $strict = false)
     {
     {
+        if (is_numeric($key)) {
+            return $key;
+        } elseif ($key instanceof Expression) {
+            return $key->getValue();
+        }
+
         $key = trim($key);
         $key = trim($key);
         if (strpos($key, '$.') && false === strpos($key, '(')) {
         if (strpos($key, '$.') && false === strpos($key, '(')) {
             // JSON字段支持
             // JSON字段支持

+ 9 - 3
thinkphp/library/think/db/builder/Sqlite.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
@@ -52,12 +52,18 @@ class Sqlite extends Builder
     /**
     /**
      * 字段和表名处理
      * 字段和表名处理
      * @access protected
      * @access protected
-     * @param string $key
+     * @param mixed  $key
      * @param array  $options
      * @param array  $options
      * @return string
      * @return string
      */
      */
-    protected function parseKey($key, $options = [])
+    protected function parseKey($key, $options = [], $strict = false)
     {
     {
+        if (is_numeric($key)) {
+            return $key;
+        } elseif ($key instanceof Expression) {
+            return $key->getValue();
+        }
+
         $key = trim($key);
         $key = trim($key);
         if (strpos($key, '.')) {
         if (strpos($key, '.')) {
             list($table, $key) = explode('.', $key, 2);
             list($table, $key) = explode('.', $key, 2);

+ 32 - 18
thinkphp/library/think/db/builder/Sqlsrv.php

@@ -12,6 +12,7 @@
 namespace think\db\builder;
 namespace think\db\builder;
 
 
 use think\db\Builder;
 use think\db\Builder;
+use think\db\Expression;
 
 
 /**
 /**
  * Sqlsrv数据库驱动
  * Sqlsrv数据库驱动
@@ -34,25 +35,29 @@ class Sqlsrv extends Builder
      */
      */
     protected function parseOrder($order, $options = [])
     protected function parseOrder($order, $options = [])
     {
     {
-        if (is_array($order)) {
-            $array = [];
-            foreach ($order as $key => $val) {
-                if (is_numeric($key)) {
-                    if (false === strpos($val, '(')) {
-                        $array[] = $this->parseKey($val, $options);
-                    } elseif ('[rand]' == $val) {
-                        $array[] = $this->parseRand();
-                    } else {
-                        $array[] = $val;
-                    }
+        if (empty($order)) {
+            return ' ORDER BY rand()';
+        }
+
+        $array = [];
+        foreach ($order as $key => $val) {
+            if ($val instanceof Expression) {
+                $array[] = $val->getValue();
+            } elseif (is_numeric($key)) {
+                if (false === strpos($val, '(')) {
+                    $array[] = $this->parseKey($val, $options);
+                } elseif ('[rand]' == $val) {
+                    $array[] = $this->parseRand();
                 } else {
                 } else {
-                    $sort    = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';
-                    $array[] = $this->parseKey($key, $options) . ' ' . $sort;
+                    $array[] = $val;
                 }
                 }
+            } else {
+                $sort    = in_array(strtolower(trim($val)), ['asc', 'desc'], true) ? ' ' . $val : '';
+                $array[] = $this->parseKey($key, $options, true) . ' ' . $sort;
             }
             }
-            $order = implode(',', $array);
         }
         }
-        return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()';
+
+        return ' ORDER BY ' . implode(',', $array);
     }
     }
 
 
     /**
     /**
@@ -68,12 +73,17 @@ class Sqlsrv extends Builder
     /**
     /**
      * 字段和表名处理
      * 字段和表名处理
      * @access protected
      * @access protected
-     * @param string $key
+     * @param mixed  $key
      * @param array  $options
      * @param array  $options
      * @return string
      * @return string
      */
      */
-    protected function parseKey($key, $options = [])
+    protected function parseKey($key, $options = [], $strict = false)
     {
     {
+        if (is_numeric($key)) {
+            return $key;
+        } elseif ($key instanceof Expression) {
+            return $key->getValue();
+        }
         $key = trim($key);
         $key = trim($key);
         if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) {
         if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) {
             list($table, $key) = explode('.', $key, 2);
             list($table, $key) = explode('.', $key, 2);
@@ -84,7 +94,11 @@ class Sqlsrv extends Builder
                 $table = $options['alias'][$table];
                 $table = $options['alias'][$table];
             }
             }
         }
         }
-        if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
+
+        if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) {
+            throw new Exception('not support data:' . $key);
+        }
+        if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {
             $key = '[' . $key . ']';
             $key = '[' . $key . ']';
         }
         }
         if (isset($table)) {
         if (isset($table)) {

+ 1 - 1
thinkphp/library/think/db/connector/Mysql.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/db/connector/Pgsql.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/db/connector/Sqlite.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 4 - 1
thinkphp/library/think/db/connector/Sqlsrv.php

@@ -50,7 +50,10 @@ class Sqlsrv extends Connection
     public function getFields($tableName)
     public function getFields($tableName)
     {
     {
         list($tableName) = explode(' ', $tableName);
         list($tableName) = explode(' ', $tableName);
-        $sql             = "SELECT   column_name,   data_type,   column_default,   is_nullable
+        $tableNames      = explode('.', $tableName);
+        $tableName       = isset($tableNames[1]) ? $tableNames[1] : $tableNames[0];
+
+        $sql = "SELECT   column_name,   data_type,   column_default,   is_nullable
         FROM    information_schema.tables AS t
         FROM    information_schema.tables AS t
         JOIN    information_schema.columns AS c
         JOIN    information_schema.columns AS c
         ON  t.table_catalog = c.table_catalog
         ON  t.table_catalog = c.table_catalog

+ 1 - 1
thinkphp/library/think/db/exception/BindParamException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/db/exception/DataNotFoundException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/db/exception/ModelNotFoundException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/debug/Console.php

@@ -137,7 +137,7 @@ JS;
                     }
                     }
                     break;
                     break;
                 case '错误':
                 case '错误':
-                    $msg    = str_replace("\n", '\n', $m);
+                    $msg    = str_replace("\n", '\n', json_encode($m));
                     $style  = 'color:#F4006B;font-size:14px;';
                     $style  = 'color:#F4006B;font-size:14px;';
                     $line[] = "console.error(\"%c{$msg}\", \"{$style}\");";
                     $line[] = "console.error(\"%c{$msg}\", \"{$style}\");";
                     break;
                     break;

+ 1 - 1
thinkphp/library/think/debug/Html.php

@@ -53,7 +53,7 @@ class Html
             return false;
             return false;
         }
         }
         // 获取基本信息
         // 获取基本信息
-        $runtime = number_format(microtime(true) - THINK_START_TIME, 10);
+        $runtime = number_format(microtime(true) - THINK_START_TIME, 10, '.', '');
         $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
         $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
         $mem     = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
         $mem     = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);
 
 

+ 1 - 1
thinkphp/library/think/exception/DbException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/exception/ErrorException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

+ 1 - 1
thinkphp/library/think/exception/PDOException.php

@@ -2,7 +2,7 @@
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 // +----------------------------------------------------------------------
 // +----------------------------------------------------------------------

Some files were not shown because too many files changed in this diff