Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
controller.php
1<?php
2
4
14
15Loc::loadMessages(__FILE__);
16
17abstract class Controller
18{
19 const EVENT_ON_BEFORE_ACTION = 'onBeforeAction';
20
21 const ERROR_REQUIRED_PARAMETER = 'REPORT_CONTROLLER_22001';
22 const ERROR_UNKNOWN_ACTION = 'REPORT_CONTROLLER_22002';
23
24 const STATUS_SUCCESS = 'success';
25 const STATUS_DENIED = 'denied';
26 const STATUS_ERROR = 'error';
27 const STATUS_NEED_AUTH = 'need_auth';
28 const STATUS_INVALID_SIGN = 'invalid_sign';
29 const STATUS_RESTRICTION = 'restriction';
30
32 protected $action;
36 protected $realActionName;
40 protected $request;
41
45 public function __construct()
46 {
47 $this->errorCollection = new ErrorCollection;
48 $this->request = Context::getCurrent()->getRequest();
49
50 $this->init();
51 }
52
58 protected function init()
59 {}
60
66 protected function end()
67 {
69 \CMain::finalActions();
70 die;
71 }
72
78 public function exec()
79 {
80 try
81 {
82 //todo move in processBeforeAction()
83 if($this->request->isPost())
84 {
85 \CUtil::jSPostUnescape();
86 $this->request->addFilter(new PostDecodeFilter);
87 }
88
89 $this->resolveAction();
90 $this->checkAction();
91
92 $this->checkRequiredModules();
93
94 if(!$this->prepareParams())
95 {
96 $this->sendJsonErrorResponse();
97 }
98
99 $action = $this->getAction();
100 if(
101 $this->processBeforeAction($action) === true &&
102 $this->triggerOnBeforeAction($action) === true
103 )
104 {
105 $this->runAction();
106 }
107 }
108 catch(\Exception $e)
109 {
110 $this->runProcessingException($e);
111 }
112 }
113
122 protected function triggerOnBeforeAction($action)
123 {
124 $event = new Event('report', static::EVENT_ON_BEFORE_ACTION . $action, array(
125 'action' => $action,
126 'controller' => $this,
127 ));
128 $event->send($this);
129
130 if($event->getResults())
131 {
132 foreach($event->getResults() as $eventResult)
133 {
134 if($eventResult->getType() != EventResult::SUCCESS)
135 {
136 return false;
137 }
138 }
139 }
140
141 return true;
142 }
143
148 protected function getUser()
149 {
150 global $USER;
151
152 return $USER;
153 }
154
161 protected function sendJsonResponse($response, $params = null)
162 {
163 if(!defined('PUBLIC_AJAX_MODE'))
164 {
165 define('PUBLIC_AJAX_MODE', true);
166 }
167
168 global $APPLICATION;
169 $APPLICATION->restartBuffer();
170
171 if(!empty($params['http_status']) && $params['http_status'] == 403)
172 {
173 header('HTTP/1.0 403 Forbidden', true, 403);
174 }
175 if(!empty($params['http_status']) && $params['http_status'] == 500)
176 {
177 header('HTTP/1.0 500 Internal Server Error', true, 500);
178 }
179 if(!empty($params['http_status']) && $params['http_status'] == 510)
180 {
181 header('HTTP/1.0 510 Not Extended', true, 510);
182 }
183
184 header('Content-Type:application/json; charset=UTF-8');
185 echo Json::encode($response);
186
187 $this->end();
188 }
189
194 protected function sendJsonErrorResponse()
195 {
196 $errors = array();
197 foreach($this->getErrors() as $error)
198 {
200 $errors[] = array(
201 'message' => $error->getMessage(),
202 'code' => $error->getCode(),
203 );
204 }
205 unset($error);
206 $this->sendJsonResponse(array(
207 'status' => self::STATUS_ERROR,
208 'errors' => $errors,
209 ));
210 }
211
217 protected function sendJsonAccessDeniedResponse($message = '')
218 {
219 $this->sendJsonResponse(array(
220 'status' => self::STATUS_DENIED,
221 'message' => $message,
222 ));
223 }
224
230 protected function sendJsonInvalidSignResponse($message = '')
231 {
232 $this->sendJsonResponse(array(
233 'status' => self::STATUS_INVALID_SIGN,
234 'message' => $message,
235 ));
236 }
237
243 protected function sendJsonSuccessResponse(array $response = array())
244 {
245 $response['status'] = self::STATUS_SUCCESS;
246 $this->sendJsonResponse($response);
247 }
248
255 protected function sendResponse($response)
256 {
257 global $APPLICATION;
258 $APPLICATION->restartBuffer();
259
260 echo $response;
261
262 $this->end();
263 }
264
269 public function getErrors()
270 {
271 return $this->errorCollection->toArray();
272 }
273
279 public function getErrorByCode($code)
280 {
281 return $this->errorCollection->getErrorByCode($code);
282 }
283
289 protected function resolveAction()
290 {
291 $listOfActions = $this->normalizeListOfAction($this->listActions());
292 $action = mb_strtolower($this->action);
293
294 if(!isset($listOfActions[$action]))
295 {
296 $this->errorCollection->add(array(new Error(Loc::getMessage('REPORT_CONTROLLER_ERROR_UNKNOWN_ACTION',
297 array('#ACTION#' => $action)), self::ERROR_UNKNOWN_ACTION)));
298 return $this;
299 }
300
301 $this->realActionName = $action;
302 $description = $listOfActions[$this->realActionName];
303 $this->setAction($description['name'], $description);
304
305 return $this;
306 }
307
308 //todo refactor BaseComponent + Controller normalizeListOfAction, resolveAction.
309 //you can use composition in BaseComponent
315 protected function normalizeListOfAction(array $listOfActions)
316 {
317 $normalized = array();
318 foreach($listOfActions as $action => $description)
319 {
320 if(!is_string($action))
321 {
322 $normalized[$description] = $this->normalizeActionDescription($description, $description);
323 }
324 else
325 {
326 $normalized[$action] = $this->normalizeActionDescription($action, $description);
327 }
328 }
329 unset($action, $description);
330
331 return array_change_key_case($normalized, CASE_LOWER);
332 }
333
350 protected function normalizeActionDescription($action, $description)
351 {
352 if(!is_array($description))
353 {
354 $description = array(
355 'method' => array('GET'),
356 'name' => $description,
357 'check_csrf_token' => false,
358 'redirect_on_auth' => true,
359 'close_session' => false,
360 );
361 }
362 if(empty($description['name']))
363 {
364 $description['name'] = $action;
365 }
366 if(!isset($description['redirect_on_auth']))
367 {
368 $description['redirect_on_auth'] = false;
369 }
370 if(!isset($description['close_session']))
371 {
372 $description['close_session'] = false;
373 }
374
375 return $description;
376 }
377
383 protected function checkAction()
384 {
385 if($this->errorCollection->count())
386 {
387 $this->sendJsonErrorResponse();
388 }
389 $description = $this->getActionDescription();
390
391 if(!$this->getUser() || !$this->getUser()->getId())
392 {
393 if($description['redirect_on_auth'])
394 {
395 LocalRedirect(SITE_DIR . 'auth/?backurl=' .
396 urlencode(Application::getInstance()->getContext()->getRequest()->getRequestUri()));
397 }
398 else
399 {
401 }
402 }
403
404 //if does not exist check_csrf_token we have to check csrf for only POST method.
405 if(
406 (isset($description['check_csrf_token']) && $description['check_csrf_token'] === true) ||
407 ($this->request->isPost() && !isset($description['check_csrf_token'])))
408 {
409 //in BDisk we have token_sid
410 if(!check_bitrix_sessid() && !check_bitrix_sessid('token_sid'))
411 {
413 }
414 }
415
416 if(!in_array($this->request->getRequestMethod(), $description['method']))
417 {
418 $this->sendJsonAccessDeniedResponse('Wrong method for current action');
419 }
420 }
421
454 protected function listActions()
455 {
456 return array();
457 }
458
463 public function getAction()
464 {
465 return $this->action;
466 }
467
472 public function getActionDescription()
473 {
474 return $this->actionDescription;
475 }
476
483 public function setAction($action, array $description)
484 {
485 $this->action = $action;
486 $this->actionDescription = $description;
487
488 return $this;
489 }
490
496 public function setActionName($action)
497 {
498 $this->action = $action;
499 return $this;
500 }
501
506 protected function checkRequiredModules()
507 {}
508
513 protected function prepareParams()
514 {
515 return true;
516 }
517
523 protected function processBeforeAction($actionName)
524 {
525 return true;
526 }
527
528 protected function runAction()
529 {
530 $description = $this->getActionDescription();
531 if($description['close_session'] === true)
532 {
533 //todo be careful by using this features.
534 session_write_close();
535 }
536 $actionMethod = 'processAction' . $this->getAction();
537
538 return $this->$actionMethod();
539 }
540
546 protected function runProcessingException(\Exception $e)
547 {
548// throw $e;
549 $this->errorCollection->add(array(new Error($e->getMessage())));
550 $this->sendJsonErrorResponse();
551 }
552
558 {
560 }
561
567 {
568 $this->sendJsonAccessDeniedResponse('Wrong csrf token');
569 }
570
575 protected function getApplication()
576 {
577 global $APPLICATION;
578 return $APPLICATION;
579 }
580
588 protected function checkRequiredInputParams(array $inputParams, array $required)
589 {
590 foreach ($required as $item)
591 {
592 if(!isset($inputParams[$item]) || (!$inputParams[$item] &&
593 !(is_string($inputParams[$item]) && mb_strlen($inputParams[$item]))))
594 {
595 $this->errorCollection->add(array(new Error(
596 Loc::getMessage('REPORT_CONTROLLER_ERROR_REQUIRED_PARAMETER',
597 array('#PARAM#' => $item)), self::ERROR_REQUIRED_PARAMETER)));
598 return false;
599 }
600 }
601
602 return true;
603 }
604
611 protected function checkRequiredPostParams(array $required)
612 {
613 $params = array();
614 foreach($required as $item)
615 {
616 $params[$item] = $this->request->getPost($item);
617 }
618 unset($item);
619
620 return $this->checkRequiredInputParams($params, $required);
621 }
622
629 protected function checkRequiredGetParams(array $required)
630 {
631 $params = array();
632 foreach($required as $item)
633 {
634 $params[$item] = $this->request->getQuery($item);
635 }
636 unset($item);
637
638 return $this->checkRequiredInputParams($params, $required);
639 }
640
647 protected function checkRequiredFilesParams(array $required)
648 {
649 $params = array();
650 foreach($required as $item)
651 {
652 $params[$item] = $this->request->getFile($item);
653 }
654 unset($item);
655
656 return $this->checkRequiredInputParams($params, $required);
657 }
658
663 protected function isAjaxRequest()
664 {
665 return $this->request->isAjaxRequest();
666 }
667}
static getCurrent()
Definition context.php:241
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
sendJsonSuccessResponse(array $response=array())
checkRequiredFilesParams(array $required)
setAction($action, array $description)
sendJsonResponse($response, $params=null)
normalizeActionDescription($action, $description)
checkRequiredPostParams(array $required)
checkRequiredGetParams(array $required)
normalizeListOfAction(array $listOfActions)
checkRequiredInputParams(array $inputParams, array $required)