作者 Karson

新增跨域检测方法

修复本地上传后cdnurl获取不正确的BUG
@@ -56,6 +56,8 @@ class Ajax extends Backend @@ -56,6 +56,8 @@ class Ajax extends Backend
56 public function upload() 56 public function upload()
57 { 57 {
58 Config::set('default_return_type', 'json'); 58 Config::set('default_return_type', 'json');
  59 + //必须设定cdnurl为空,否则cdnurl函数计算错误
  60 + Config::set('upload.cdnurl', '');
59 $chunkid = $this->request->post("chunkid"); 61 $chunkid = $this->request->post("chunkid");
60 if ($chunkid) { 62 if ($chunkid) {
61 if (!Config::get('upload.chunking')) { 63 if (!Config::get('upload.chunking')) {
@@ -75,7 +77,7 @@ class Ajax extends Backend @@ -75,7 +77,7 @@ class Ajax extends Backend
75 } catch (UploadException $e) { 77 } catch (UploadException $e) {
76 $this->error($e->getMessage()); 78 $this->error($e->getMessage());
77 } 79 }
78 - $this->success(__('Uploaded successful'), '', ['url' => $attachment->url]); 80 + $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
79 } elseif ($method == 'clean') { 81 } elseif ($method == 'clean') {
80 //删除冗余的分片文件 82 //删除冗余的分片文件
81 try { 83 try {
@@ -108,7 +110,7 @@ class Ajax extends Backend @@ -108,7 +110,7 @@ class Ajax extends Backend
108 $this->error($e->getMessage()); 110 $this->error($e->getMessage());
109 } 111 }
110 112
111 - $this->success(__('Uploaded successful'), '', ['url' => $attachment->url]); 113 + $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
112 } 114 }
113 115
114 } 116 }
@@ -50,6 +50,8 @@ class Common extends Api @@ -50,6 +50,8 @@ class Common extends Api
50 public function upload() 50 public function upload()
51 { 51 {
52 Config::set('default_return_type', 'json'); 52 Config::set('default_return_type', 'json');
  53 + //必须设定cdnurl为空,否则cdnurl函数计算错误
  54 + Config::set('upload.cdnurl', '');
53 $chunkid = $this->request->post("chunkid"); 55 $chunkid = $this->request->post("chunkid");
54 if ($chunkid) { 56 if ($chunkid) {
55 if (!Config::get('upload.chunking')) { 57 if (!Config::get('upload.chunking')) {
@@ -69,7 +71,7 @@ class Common extends Api @@ -69,7 +71,7 @@ class Common extends Api
69 } catch (UploadException $e) { 71 } catch (UploadException $e) {
70 $this->error($e->getMessage()); 72 $this->error($e->getMessage());
71 } 73 }
72 - $this->success(__('Uploaded successful'), ['url' => $attachment->url]); 74 + $this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
73 } elseif ($method == 'clean') { 75 } elseif ($method == 'clean') {
74 //删除冗余的分片文件 76 //删除冗余的分片文件
75 try { 77 try {
@@ -102,7 +104,7 @@ class Common extends Api @@ -102,7 +104,7 @@ class Common extends Api
102 $this->error($e->getMessage()); 104 $this->error($e->getMessage());
103 } 105 }
104 106
105 - $this->success(__('Uploaded successful'), ['url' => $attachment->url]); 107 + $this->success(__('Uploaded successful'), ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
106 } 108 }
107 109
108 } 110 }
@@ -97,7 +97,7 @@ if (!function_exists('is_really_writable')) { @@ -97,7 +97,7 @@ if (!function_exists('is_really_writable')) {
97 97
98 /** 98 /**
99 * 判断文件或文件夹是否可写 99 * 判断文件或文件夹是否可写
100 - * @param string $file 文件或目录 100 + * @param string $file 文件或目录
101 * @return bool 101 * @return bool
102 */ 102 */
103 function is_really_writable($file) 103 function is_really_writable($file)
@@ -362,3 +362,36 @@ if (!function_exists('hsv2rgb')) { @@ -362,3 +362,36 @@ if (!function_exists('hsv2rgb')) {
362 ]; 362 ];
363 } 363 }
364 } 364 }
  365 +
  366 +if (!function_exists('cors_request_check')) {
  367 + /**
  368 + * 跨域检测
  369 + */
  370 + function cors_request_check()
  371 + {
  372 + if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN']) {
  373 + $info = parse_url($_SERVER['HTTP_ORIGIN']);
  374 + $domainArr = explode(',', config('fastadmin.cors_request_domain'));
  375 + $domainArr[] = request()->host();
  376 + if (in_array("*", $domainArr) || in_array($_SERVER['HTTP_ORIGIN'], $domainArr) || (isset($info['host']) && in_array($info['host'], $domainArr))) {
  377 + header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
  378 + } else {
  379 + header('HTTP/1.1 403 Forbidden');
  380 + exit;
  381 + }
  382 +
  383 + header('Access-Control-Allow-Credentials: true');
  384 + header('Access-Control-Max-Age: 86400');
  385 +
  386 + if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  387 + if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
  388 + header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
  389 + }
  390 + if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
  391 + header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
  392 + }
  393 + exit;
  394 + }
  395 + }
  396 + }
  397 +}
@@ -91,24 +91,8 @@ class Api @@ -91,24 +91,8 @@ class Api
91 */ 91 */
92 protected function _initialize() 92 protected function _initialize()
93 { 93 {
94 - if (Config::get('url_domain_deploy')) {  
95 - $domain = Route::rules('domain');  
96 - if (isset($domain['api'])) {  
97 - if (isset($_SERVER['HTTP_ORIGIN'])) {  
98 - header("Access-Control-Allow-Origin: " . $this->request->server('HTTP_ORIGIN'));  
99 - header('Access-Control-Allow-Credentials: true');  
100 - header('Access-Control-Max-Age: 86400');  
101 - }  
102 - if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {  
103 - if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {  
104 - header("Access-Control-Allow-Methods: GET, POST, OPTIONS");  
105 - }  
106 - if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {  
107 - header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");  
108 - }  
109 - }  
110 - }  
111 - } 94 + //跨域请求检测
  95 + cors_request_check();
112 96
113 //移除HTML标签 97 //移除HTML标签
114 $this->request->filter('trim,strip_tags,htmlspecialchars'); 98 $this->request->filter('trim,strip_tags,htmlspecialchars');
@@ -164,7 +148,7 @@ class Api @@ -164,7 +148,7 @@ class Api
164 */ 148 */
165 protected function loadlang($name) 149 protected function loadlang($name)
166 { 150 {
167 - $name = Loader::parseName($name); 151 + $name = Loader::parseName($name);
168 Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php'); 152 Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
169 } 153 }
170 154
@@ -230,8 +214,8 @@ class Api @@ -230,8 +214,8 @@ class Api
230 /** 214 /**
231 * 前置操作 215 * 前置操作
232 * @access protected 216 * @access protected
233 - * @param string $method 前置操作方法名  
234 - * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]] 217 + * @param string $method 前置操作方法名
  218 + * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
235 * @return void 219 * @return void
236 */ 220 */
237 protected function beforeAction($method, $options = []) 221 protected function beforeAction($method, $options = [])
@@ -273,11 +257,11 @@ class Api @@ -273,11 +257,11 @@ class Api
273 /** 257 /**
274 * 验证数据 258 * 验证数据
275 * @access protected 259 * @access protected
276 - * @param array $data 数据  
277 - * @param string|array $validate 验证器名或者验证规则数组  
278 - * @param array $message 提示信息  
279 - * @param bool $batch 是否批量验证  
280 - * @param mixed $callback 回调方法(闭包) 260 + * @param array $data 数据
  261 + * @param string|array $validate 验证器名或者验证规则数组
  262 + * @param array $message 提示信息
  263 + * @param bool $batch 是否批量验证
  264 + * @param mixed $callback 回调方法(闭包)
281 * @return array|string|true 265 * @return array|string|true
282 * @throws ValidateException 266 * @throws ValidateException
283 */ 267 */
@@ -165,9 +165,12 @@ class Config extends Model @@ -165,9 +165,12 @@ class Config extends Model
165 { 165 {
166 $uploadcfg = config('upload'); 166 $uploadcfg = config('upload');
167 167
  168 + $uploadurl = request()->module() ? $uploadcfg['uploadurl'] : ($uploadcfg['uploadurl'] === 'ajax/upload' ? 'index/' . $uploadcfg['uploadurl'] : $uploadcfg['uploadurl']);
  169 +
  170 + $uploadurl = url($uploadurl, '', false, true);
168 $upload = [ 171 $upload = [
169 'cdnurl' => $uploadcfg['cdnurl'], 172 'cdnurl' => $uploadcfg['cdnurl'],
170 - 'uploadurl' => $uploadcfg['uploadurl'], 173 + 'uploadurl' => $uploadurl,
171 'bucket' => 'local', 174 'bucket' => 'local',
172 'maxsize' => $uploadcfg['maxsize'], 175 'maxsize' => $uploadcfg['maxsize'],
173 'mimetype' => $uploadcfg['mimetype'], 176 'mimetype' => $uploadcfg['mimetype'],
@@ -175,6 +178,7 @@ class Config extends Model @@ -175,6 +178,7 @@ class Config extends Model
175 'chunksize' => $uploadcfg['chunksize'], 178 'chunksize' => $uploadcfg['chunksize'],
176 'multipart' => [], 179 'multipart' => [],
177 'multiple' => $uploadcfg['multiple'], 180 'multiple' => $uploadcfg['multiple'],
  181 + 'storage' => 'local'
178 ]; 182 ];
179 return $upload; 183 return $upload;
180 } 184 }
@@ -273,6 +273,8 @@ return [ @@ -273,6 +273,8 @@ return [
273 'login_background' => "/assets/img/loginbg.jpg", 273 'login_background' => "/assets/img/loginbg.jpg",
274 //是否启用多级菜单导航 274 //是否启用多级菜单导航
275 'multiplenav' => false, 275 'multiplenav' => false,
  276 + //允许跨域的域名,多个以,分隔
  277 + 'cors_request_domain' => 'localhost,127.0.0.1',
276 //自动检测更新 278 //自动检测更新
277 'checkupdate' => false, 279 'checkupdate' => false,
278 //版本号 280 //版本号
@@ -12,7 +12,7 @@ use think\Lang; @@ -12,7 +12,7 @@ use think\Lang;
12 class Ajax extends Frontend 12 class Ajax extends Frontend
13 { 13 {
14 14
15 - protected $noNeedLogin = ['lang']; 15 + protected $noNeedLogin = ['lang', 'upload'];
16 protected $noNeedRight = ['*']; 16 protected $noNeedRight = ['*'];
17 protected $layout = ''; 17 protected $layout = '';
18 18
@@ -68,6 +68,9 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine @@ -68,6 +68,9 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
68 options = $.extend({ 68 options = $.extend({
69 type: "POST", 69 type: "POST",
70 dataType: "json", 70 dataType: "json",
  71 + xhrFields: {
  72 + withCredentials: true
  73 + },
71 success: function (ret) { 74 success: function (ret) {
72 index && Layer.close(index); 75 index && Layer.close(index);
73 ret = Fast.events.onAjaxResponse(ret); 76 ret = Fast.events.onAjaxResponse(ret);
@@ -731,6 +731,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u @@ -731,6 +731,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
731 options = $.extend({ 731 options = $.extend({
732 type: "POST", 732 type: "POST",
733 dataType: "json", 733 dataType: "json",
  734 + xhrFields: {
  735 + withCredentials: true
  736 + },
734 success: function (ret) { 737 success: function (ret) {
735 index && Layer.close(index); 738 index && Layer.close(index);
736 ret = Fast.events.onAjaxResponse(ret); 739 ret = Fast.events.onAjaxResponse(ret);
@@ -10229,8 +10232,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef @@ -10229,8 +10232,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
10229 }, 10232 },
10230 faselect: function (form) { 10233 faselect: function (form) {
10231 //绑定fachoose选择附件事件 10234 //绑定fachoose选择附件事件
10232 - if ($(".fachoose", form).size() > 0) {  
10233 - $(".fachoose", form).on('click', function () { 10235 + if ($(".faselect,.fachoose", form).size() > 0) {
  10236 + $(".faselect,.fachoose", form).on('click', function () {
10234 var that = this; 10237 var that = this;
10235 var multiple = $(this).data("multiple") ? $(this).data("multiple") : false; 10238 var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
10236 var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : ''; 10239 var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
@@ -241,8 +241,8 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U @@ -241,8 +241,8 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
241 }, 241 },
242 faselect: function (form) { 242 faselect: function (form) {
243 //绑定fachoose选择附件事件 243 //绑定fachoose选择附件事件
244 - if ($(".fachoose", form).size() > 0) {  
245 - $(".fachoose", form).on('click', function () { 244 + if ($(".faselect,.fachoose", form).size() > 0) {
  245 + $(".faselect,.fachoose", form).on('click', function () {
246 var that = this; 246 var that = this;
247 var multiple = $(this).data("multiple") ? $(this).data("multiple") : false; 247 var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
248 var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : ''; 248 var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
@@ -724,6 +724,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u @@ -724,6 +724,9 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
724 options = $.extend({ 724 options = $.extend({
725 type: "POST", 725 type: "POST",
726 dataType: "json", 726 dataType: "json",
  727 + xhrFields: {
  728 + withCredentials: true
  729 + },
727 success: function (ret) { 730 success: function (ret) {
728 index && Layer.close(index); 731 index && Layer.close(index);
729 ret = Fast.events.onAjaxResponse(ret); 732 ret = Fast.events.onAjaxResponse(ret);