Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
controller.php
1<?php
2
4
13
14Loc::loadMessages(__FILE__);
15
21abstract class Controller implements IErrorable
22{
23 const ERROR_REQUIRED_PARAMETER = 'LISTS_CONTROLLER_22001';
24 const ERROR_UNKNOWN_ACTION = 'LISTS_CONTROLLER_22002';
25
26 const STATUS_SUCCESS = 'success';
27 const STATUS_PROCESSING = 'processing';
28 const STATUS_COMPLETED = 'completed';
29 const STATUS_DENIED = 'denied';
30 const STATUS_ERROR = 'error';
31 const STATUS_NEED_AUTH = 'need_auth';
32 const STATUS_INVALID_SIGN = 'invalid_sign';
33
35 protected $action;
39 protected $realActionName;
43 protected $request;
44
45 public function __construct()
46 {
47 $this->errorCollection = new ErrorCollection;
48 $this->request = Context::getCurrent()->getRequest();
49 }
50
51 protected function end()
52 {
53 include($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/include/epilog_after.php");
54 die;
55 }
56
57 public function exec()
58 {
59 try
60 {
61 if($this->request->isPost())
62 {
63 \CUtil::jSPostUnescape();
64 $this->request->addFilter(new PostDecodeFilter);
65 }
66
67 $this->resolveAction();
68 $this->checkAction();
69
70 $this->checkRequiredModules();
71
72 if(!$this->prepareParams())
73 {
74 $this->sendJsonErrorResponse();
75 }
76
77 //todo create Event!
78 if($this->processBeforeAction($this->getAction()) !== false)
79 {
80 $this->runAction();
81 }
82 }
83 catch(\Exception $e)
84 {
85 $this->runProcessingException($e);
86 }
87 }
88
92 protected function getUser()
93 {
94 global $USER;
95 return $USER;
96 }
97
98 protected function sendJsonResponse($response, $params = null)
99 {
100 if(!defined('PUBLIC_AJAX_MODE'))
101 {
102 define('PUBLIC_AJAX_MODE', true);
103 }
104
105 global $APPLICATION;
106 $APPLICATION->restartBuffer();
107
108 if(!empty($params['http_status']) && $params['http_status'] == 403)
109 {
110 header('HTTP/1.0 403 Forbidden', true, 403);
111 }
112 if(!empty($params['http_status']) && $params['http_status'] == 500)
113 {
114 header('HTTP/1.0 500 Internal Server Error', true, 500);
115 }
116
117 header('Content-Type:application/json; charset=UTF-8');
118 echo Json::encode($response);
119
120 $this->end();
121 }
122
123 protected function sendJsonErrorResponse()
124 {
125 $errors = array();
126 foreach($this->getErrors() as $error)
127 {
129 $errors[] = array(
130 'message' => $error->getMessage(),
131 'code' => $error->getCode(),
132 );
133 }
134 unset($error);
135 $this->sendJsonResponse(array(
136 'status' => self::STATUS_ERROR,
137 'errors' => $errors,
138 ));
139 }
140
141 protected function sendJsonAccessDeniedResponse($message = '')
142 {
143 $this->sendJsonResponse(array(
144 'status' => self::STATUS_DENIED,
145 'message' => $message,
146 ));
147 }
148
149 protected function sendJsonInvalidSignResponse($message = '')
150 {
151 $this->sendJsonResponse(array(
152 'status' => self::STATUS_INVALID_SIGN,
153 'message' => $message,
154 ));
155 }
156
157 protected function sendJsonSuccessResponse(array $response = array())
158 {
159 $response['status'] = self::STATUS_SUCCESS;
160 $this->sendJsonResponse($response);
161 }
162
163 protected function sendJsonProcessingResponse(array $response = array())
164 {
165 $response['status'] = self::STATUS_PROCESSING;
166 $this->sendJsonResponse($response);
167 }
168
169 protected function sendJsonCompletedResponse(array $response = array())
170 {
171 $response['status'] = self::STATUS_COMPLETED;
172 $this->sendJsonResponse($response);
173 }
174
175 protected function sendResponse($response)
176 {
177 global $APPLICATION;
178 $APPLICATION->restartBuffer();
179
180 echo $response;
181
182 $this->end();
183 }
184
188 public function getErrors()
189 {
190 return $this->errorCollection->toArray();
191 }
192
196 public function getErrorsByCode($code)
197 {
198 return $this->errorCollection->getErrorsByCode($code);
199 }
200
204 public function getErrorByCode($code)
205 {
206 return $this->errorCollection->getErrorByCode($code);
207 }
208
209 protected function resolveAction()
210 {
211 $listOfActions = $this->normalizeListOfAction($this->listOfActions());
212 $action = mb_strtolower($this->action);
213
214 if(!isset($listOfActions[$action]))
215 {
216 $this->errorCollection->add(array(new Error(Loc::getMessage('LISTS_CONTROLLER_ERROR_UNKNOWN_ACTION', array('#ACTION#' => $action)), self::ERROR_UNKNOWN_ACTION)));
217 return $this;
218 }
219
220 $this->realActionName = $action;
221 $description = $listOfActions[$this->realActionName];
222 $this->setAction($description['name'], $description);
223
224 return $this;
225 }
226
227 //todo refactor BaseComponent + Controller normalizeListOfAction, resolveAction.
228 //you can use composition in BaseComponent
229 protected function normalizeListOfAction(array $listOfActions)
230 {
231 $normalized = array();
232 foreach($listOfActions as $action => $description)
233 {
234 if(!is_string($action))
235 {
236 $normalized[$description] = $this->normalizeActionDescription($description, $description);
237 }
238 else
239 {
240 $normalized[$action] = $this->normalizeActionDescription($action, $description);
241 }
242 }
243 unset($action, $description);
244
245 return array_change_key_case($normalized, CASE_LOWER);
246 }
247
248 protected function normalizeActionDescription($action, $description)
249 {
250 if(!is_array($description))
251 {
252 $description = array(
253 'method' => array('GET'),
254 'name' => $description,
255 'check_csrf_token' => false,
256 'redirect_on_auth' => true,
257 'close_session' => false,
258 );
259 }
260 if(empty($description['name']))
261 {
262 $description['name'] = $action;
263 }
264 if(!isset($description['redirect_on_auth']))
265 {
266 $description['redirect_on_auth'] = false;
267 }
268 if(!isset($description['close_session']))
269 {
270 $description['close_session'] = false;
271 }
272
273 return $description;
274 }
275
276 protected function checkAction()
277 {
278 if($this->errorCollection->hasErrors())
279 {
280 $this->sendJsonErrorResponse();
281 }
282 $description = $this->getActionDescription();
283
284 if(!$this->getUser() || !$this->getUser()->getId())
285 {
286 if($description['redirect_on_auth'])
287 {
288 LocalRedirect(SITE_DIR . 'auth/?backurl=' . urlencode(Application::getInstance()->getContext()->getRequest()->getRequestUri()));
289 }
290 else
291 {
293 }
294 }
295
296 //if does not exist check_csrf_token we have to check csrf for only POST method.
297 if(($description['check_csrf_token'] ?? false) === true || ($this->request->isPost() && !isset($description['check_csrf_token'])))
298 {
299 //in BDisk we have token_sid
300 if(!check_bitrix_sessid() && !check_bitrix_sessid('token_sid'))
301 {
303 }
304 }
305
306 if(!in_array($this->request->getRequestMethod(), $description['method']))
307 {
308 $this->sendJsonAccessDeniedResponse('Wrong method for current action');
309 }
310 }
311
312 protected function listOfActions()
313 {
314 return array();
315 }
316
320 public function getAction()
321 {
322 return $this->action;
323 }
324
328 public function getActionDescription()
329 {
330 return $this->actionDescription;
331 }
332
338 public function setAction($action, array $description)
339 {
340 $this->action = $action;
341 $this->actionDescription = $description;
342
343 return $this;
344 }
345
350 public function setActionName($action)
351 {
352 $this->action = $action;
353 return $this;
354 }
355
356 protected function checkRequiredModules()
357 {}
358
359 protected function prepareParams()
360 {
361 return true;
362 }
363
369 protected function processBeforeAction($actionName)
370 {
371 return true;
372 }
373
374 protected function runAction()
375 {
376 $description = $this->getActionDescription();
377 if($description['close_session'] === true)
378 {
379 //todo be careful by using this features.
380 session_write_close();
381 }
382 $actionMethod = 'processAction' . $this->getAction();
383
384 return $this->$actionMethod();
385 }
386
387 protected function runProcessingException(\Exception $e)
388 {
389// throw $e;
390 $this->errorCollection->add(array(new Error($e->getMessage())));
391 $this->sendJsonErrorResponse();
392 }
393
395 {
397 }
398
400 {
401 $this->sendJsonAccessDeniedResponse('Wrong csrf token');
402 }
403
407 protected function getApplication()
408 {
409 global $APPLICATION;
410 return $APPLICATION;
411 }
412
418 protected function checkRequiredInputParams(array $inputParams, array $required)
419 {
420 foreach ($required as $item)
421 {
422 if(!isset($inputParams[$item]) || (!$inputParams[$item] && !(is_string($inputParams[$item]) && mb_strlen($inputParams[$item]))))
423 {
424 $this->errorCollection->add(array(new Error(Loc::getMessage('LISTS_CONTROLLER_ERROR_REQUIRED_PARAMETER', array('#PARAM#' => $item)), self::ERROR_REQUIRED_PARAMETER)));
425 return false;
426 }
427 }
428
429 return true;
430 }
431
432 protected function checkRequiredPostParams(array $required)
433 {
434 $params = array();
435 foreach($required as $item)
436 {
437 $params[$item] = $this->request->getPost($item);
438 }
439 unset($item);
440
441 return $this->checkRequiredInputParams($params, $required);
442 }
443
444 protected function checkRequiredGetParams(array $required)
445 {
446 $params = array();
447 foreach($required as $item)
448 {
449 $params[$item] = $this->request->getQuery($item);
450 }
451 unset($item);
452
453 return $this->checkRequiredInputParams($params, $required);
454 }
455
456 protected function checkRequiredFilesParams(array $required)
457 {
458 $params = array();
459 foreach($required as $item)
460 {
461 $params[$item] = $this->request->getFile($item);
462 }
463 unset($item);
464
465 return $this->checkRequiredInputParams($params, $required);
466 }
467
472 protected function isAjaxRequest()
473 {
474 return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
475 }
476}
sendJsonCompletedResponse(array $response=array())
sendJsonSuccessResponse(array $response=array())
checkRequiredFilesParams(array $required)
setAction($action, array $description)
sendJsonResponse($response, $params=null)
sendJsonProcessingResponse(array $response=array())
normalizeActionDescription($action, $description)
checkRequiredPostParams(array $required)
checkRequiredGetParams(array $required)
normalizeListOfAction(array $listOfActions)
checkRequiredInputParams(array $inputParams, array $required)
static getCurrent()
Definition context.php:241
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29