CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • AuthComponent
  • CookieComponent
  • CsrfComponent
  • FlashComponent
  • PaginatorComponent
  • RequestHandlerComponent
  • SecurityComponent
  1: <?php
  2: /**
  3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5:  *
  6:  * Licensed under The MIT License
  7:  * For full copyright and license information, please see the LICENSE.txt
  8:  * Redistributions of files must retain the above copyright notice.
  9:  *
 10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 11:  * @link          https://cakephp.org CakePHP(tm) Project
 12:  * @since         0.10.8
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  */
 15: namespace Cake\Controller\Component;
 16: 
 17: use Cake\Controller\Component;
 18: use Cake\Controller\Controller;
 19: use Cake\Controller\Exception\AuthSecurityException;
 20: use Cake\Controller\Exception\SecurityException;
 21: use Cake\Core\Configure;
 22: use Cake\Event\Event;
 23: use Cake\Http\Exception\BadRequestException;
 24: use Cake\Http\ServerRequest;
 25: use Cake\Routing\Router;
 26: use Cake\Utility\Hash;
 27: use Cake\Utility\Security;
 28: 
 29: /**
 30:  * The Security Component creates an easy way to integrate tighter security in
 31:  * your application. It provides methods for various tasks like:
 32:  *
 33:  * - Restricting which HTTP methods your application accepts.
 34:  * - Form tampering protection
 35:  * - Requiring that SSL be used.
 36:  * - Limiting cross controller communication.
 37:  *
 38:  * @link https://book.cakephp.org/3.0/en/controllers/components/security.html
 39:  */
 40: class SecurityComponent extends Component
 41: {
 42:     /**
 43:      * Default message used for exceptions thrown
 44:      */
 45:     const DEFAULT_EXCEPTION_MESSAGE = 'The request has been black-holed';
 46: 
 47:     /**
 48:      * Default config
 49:      *
 50:      * - `blackHoleCallback` - The controller method that will be called if this
 51:      *   request is black-hole'd.
 52:      * - `requireSecure` - List of actions that require an SSL-secured connection.
 53:      * - `requireAuth` - List of actions that require a valid authentication key. Deprecated as of 3.2.2
 54:      * - `allowedControllers` - Controllers from which actions of the current
 55:      *   controller are allowed to receive requests.
 56:      * - `allowedActions` - Actions from which actions of the current controller
 57:      *   are allowed to receive requests.
 58:      * - `unlockedFields` - Form fields to exclude from POST validation. Fields can
 59:      *   be unlocked either in the Component, or with FormHelper::unlockField().
 60:      *   Fields that have been unlocked are not required to be part of the POST
 61:      *   and hidden unlocked fields do not have their values checked.
 62:      * - `unlockedActions` - Actions to exclude from POST validation checks.
 63:      *   Other checks like requireAuth(), requireSecure() etc. will still be applied.
 64:      * - `validatePost` - Whether to validate POST data. Set to false to disable
 65:      *   for data coming from 3rd party services, etc.
 66:      *
 67:      * @var array
 68:      */
 69:     protected $_defaultConfig = [
 70:         'blackHoleCallback' => null,
 71:         'requireSecure' => [],
 72:         'requireAuth' => [],
 73:         'allowedControllers' => [],
 74:         'allowedActions' => [],
 75:         'unlockedFields' => [],
 76:         'unlockedActions' => [],
 77:         'validatePost' => true
 78:     ];
 79: 
 80:     /**
 81:      * Holds the current action of the controller
 82:      *
 83:      * @var string
 84:      */
 85:     protected $_action;
 86: 
 87:     /**
 88:      * The Session object
 89:      *
 90:      * @var \Cake\Http\Session
 91:      */
 92:     public $session;
 93: 
 94:     /**
 95:      * Component startup. All security checking happens here.
 96:      *
 97:      * @param \Cake\Event\Event $event An Event instance
 98:      * @return mixed
 99:      */
100:     public function startup(Event $event)
101:     {
102:         /** @var \Cake\Controller\Controller $controller */
103:         $controller = $event->getSubject();
104:         $request = $controller->request;
105:         $this->session = $request->getSession();
106:         $this->_action = $request->getParam('action');
107:         $hasData = ($request->getData() || $request->is(['put', 'post', 'delete', 'patch']));
108:         try {
109:             $this->_secureRequired($controller);
110:             $this->_authRequired($controller);
111: 
112:             $isNotRequestAction = !$request->getParam('requested');
113: 
114:             if ($this->_action === $this->_config['blackHoleCallback']) {
115:                 throw new AuthSecurityException(sprintf('Action %s is defined as the blackhole callback.', $this->_action));
116:             }
117: 
118:             if (!in_array($this->_action, (array)$this->_config['unlockedActions']) &&
119:                 $hasData &&
120:                 $isNotRequestAction &&
121:                 $this->_config['validatePost']
122:             ) {
123:                 $this->_validatePost($controller);
124:             }
125:         } catch (SecurityException $se) {
126:             return $this->blackHole($controller, $se->getType(), $se);
127:         }
128: 
129:         $request = $this->generateToken($request);
130:         if ($hasData && is_array($controller->getRequest()->getData())) {
131:             $request = $request->withoutData('_Token');
132:         }
133:         $controller->setRequest($request);
134:     }
135: 
136:     /**
137:      * Events supported by this component.
138:      *
139:      * @return array
140:      */
141:     public function implementedEvents()
142:     {
143:         return [
144:             'Controller.startup' => 'startup',
145:         ];
146:     }
147: 
148:     /**
149:      * Sets the actions that require a request that is SSL-secured, or empty for all actions
150:      *
151:      * @param string|array|null $actions Actions list
152:      * @return void
153:      */
154:     public function requireSecure($actions = null)
155:     {
156:         $this->_requireMethod('Secure', (array)$actions);
157:     }
158: 
159:     /**
160:      * Sets the actions that require whitelisted form submissions.
161:      *
162:      * Adding actions with this method will enforce the restrictions
163:      * set in SecurityComponent::$allowedControllers and
164:      * SecurityComponent::$allowedActions.
165:      *
166:      * @param string|array $actions Actions list
167:      * @return void
168:      * @deprecated 3.2.2 This feature is confusing and not useful.
169:      */
170:     public function requireAuth($actions)
171:     {
172:         deprecationWarning('SecurityComponent::requireAuth() will be removed in 4.0.0.');
173:         $this->_requireMethod('Auth', (array)$actions);
174:     }
175: 
176:     /**
177:      * Black-hole an invalid request with a 400 error or custom callback. If SecurityComponent::$blackHoleCallback
178:      * is specified, it will use this callback by executing the method indicated in $error
179:      *
180:      * @param \Cake\Controller\Controller $controller Instantiating controller
181:      * @param string $error Error method
182:      * @param \Cake\Controller\Exception\SecurityException|null $exception Additional debug info describing the cause
183:      * @return mixed If specified, controller blackHoleCallback's response, or no return otherwise
184:      * @see \Cake\Controller\Component\SecurityComponent::$blackHoleCallback
185:      * @link https://book.cakephp.org/3.0/en/controllers/components/security.html#handling-blackhole-callbacks
186:      * @throws \Cake\Http\Exception\BadRequestException
187:      */
188:     public function blackHole(Controller $controller, $error = '', SecurityException $exception = null)
189:     {
190:         if (!$this->_config['blackHoleCallback']) {
191:             $this->_throwException($exception);
192:         }
193: 
194:         return $this->_callback($controller, $this->_config['blackHoleCallback'], [$error, $exception]);
195:     }
196: 
197:     /**
198:      * Check debug status and throw an Exception based on the existing one
199:      *
200:      * @param \Cake\Controller\Exception\SecurityException|null $exception Additional debug info describing the cause
201:      * @throws \Cake\Http\Exception\BadRequestException
202:      * @return void
203:      */
204:     protected function _throwException($exception = null)
205:     {
206:         if ($exception !== null) {
207:             if (!Configure::read('debug') && $exception instanceof SecurityException) {
208:                 $exception->setReason($exception->getMessage());
209:                 $exception->setMessage(self::DEFAULT_EXCEPTION_MESSAGE);
210:             }
211:             throw $exception;
212:         }
213:         throw new BadRequestException(self::DEFAULT_EXCEPTION_MESSAGE);
214:     }
215: 
216:     /**
217:      * Sets the actions that require a $method HTTP request, or empty for all actions
218:      *
219:      * @param string $method The HTTP method to assign controller actions to
220:      * @param array $actions Controller actions to set the required HTTP method to.
221:      * @return void
222:      */
223:     protected function _requireMethod($method, $actions = [])
224:     {
225:         if (isset($actions[0]) && is_array($actions[0])) {
226:             $actions = $actions[0];
227:         }
228:         $this->setConfig('require' . $method, empty($actions) ? ['*'] : $actions);
229:     }
230: 
231:     /**
232:      * Check if access requires secure connection
233:      *
234:      * @param \Cake\Controller\Controller $controller Instantiating controller
235:      * @return bool true if secure connection required
236:      */
237:     protected function _secureRequired(Controller $controller)
238:     {
239:         if (is_array($this->_config['requireSecure']) &&
240:             !empty($this->_config['requireSecure'])
241:         ) {
242:             $requireSecure = $this->_config['requireSecure'];
243: 
244:             if (in_array($this->_action, $requireSecure) || $requireSecure === ['*']) {
245:                 if (!$this->getController()->getRequest()->is('ssl')) {
246:                     throw new SecurityException(
247:                         'Request is not SSL and the action is required to be secure'
248:                     );
249:                 }
250:             }
251:         }
252: 
253:         return true;
254:     }
255: 
256:     /**
257:      * Check if authentication is required
258:      *
259:      * @param \Cake\Controller\Controller $controller Instantiating controller
260:      * @return bool true if authentication required
261:      * @deprecated 3.2.2 This feature is confusing and not useful.
262:      */
263:     protected function _authRequired(Controller $controller)
264:     {
265:         $request = $controller->getRequest();
266:         if (is_array($this->_config['requireAuth']) &&
267:             !empty($this->_config['requireAuth']) &&
268:             $request->getData()
269:         ) {
270:             deprecationWarning('SecurityComponent::requireAuth() will be removed in 4.0.0.');
271:             $requireAuth = $this->_config['requireAuth'];
272: 
273:             if (in_array($request->getParam('action'), $requireAuth) || $requireAuth == ['*']) {
274:                 if ($request->getData('_Token') === null) {
275:                     throw new AuthSecurityException('\'_Token\' was not found in request data.');
276:                 }
277: 
278:                 if ($this->session->check('_Token')) {
279:                     $tData = $this->session->read('_Token');
280: 
281:                     if (!empty($tData['allowedControllers']) &&
282:                         !in_array($request->getParam('controller'), $tData['allowedControllers'])) {
283:                         throw new AuthSecurityException(
284:                             sprintf(
285:                                 'Controller \'%s\' was not found in allowed controllers: \'%s\'.',
286:                                 $request->getParam('controller'),
287:                                 implode(', ', (array)$tData['allowedControllers'])
288:                             )
289:                         );
290:                     }
291:                     if (!empty($tData['allowedActions']) &&
292:                         !in_array($request->getParam('action'), $tData['allowedActions'])
293:                     ) {
294:                         throw new AuthSecurityException(
295:                             sprintf(
296:                                 'Action \'%s::%s\' was not found in allowed actions: \'%s\'.',
297:                                 $request->getParam('controller'),
298:                                 $request->getParam('action'),
299:                                 implode(', ', (array)$tData['allowedActions'])
300:                             )
301:                         );
302:                     }
303:                 } else {
304:                     throw new AuthSecurityException('\'_Token\' was not found in session.');
305:                 }
306:             }
307:         }
308: 
309:         return true;
310:     }
311: 
312:     /**
313:      * Validate submitted form
314:      *
315:      * @param \Cake\Controller\Controller $controller Instantiating controller
316:      * @throws \Cake\Controller\Exception\AuthSecurityException
317:      * @return bool true if submitted form is valid
318:      */
319:     protected function _validatePost(Controller $controller)
320:     {
321:         $token = $this->_validToken($controller);
322:         $hashParts = $this->_hashParts($controller);
323:         $check = hash_hmac('sha1', implode('', $hashParts), Security::getSalt());
324: 
325:         if (hash_equals($check, $token)) {
326:             return true;
327:         }
328: 
329:         $msg = self::DEFAULT_EXCEPTION_MESSAGE;
330:         if (Configure::read('debug')) {
331:             $msg = $this->_debugPostTokenNotMatching($controller, $hashParts);
332:         }
333: 
334:         throw new AuthSecurityException($msg);
335:     }
336: 
337:     /**
338:      * Check if token is valid
339:      *
340:      * @param \Cake\Controller\Controller $controller Instantiating controller
341:      * @throws \Cake\Controller\Exception\SecurityException
342:      * @return string fields token
343:      */
344:     protected function _validToken(Controller $controller)
345:     {
346:         $check = $controller->getRequest()->getData();
347: 
348:         $message = '\'%s\' was not found in request data.';
349:         if (!isset($check['_Token'])) {
350:             throw new AuthSecurityException(sprintf($message, '_Token'));
351:         }
352:         if (!isset($check['_Token']['fields'])) {
353:             throw new AuthSecurityException(sprintf($message, '_Token.fields'));
354:         }
355:         if (!isset($check['_Token']['unlocked'])) {
356:             throw new AuthSecurityException(sprintf($message, '_Token.unlocked'));
357:         }
358:         if (Configure::read('debug') && !isset($check['_Token']['debug'])) {
359:             throw new SecurityException(sprintf($message, '_Token.debug'));
360:         }
361:         if (!Configure::read('debug') && isset($check['_Token']['debug'])) {
362:             throw new SecurityException('Unexpected \'_Token.debug\' found in request data');
363:         }
364: 
365:         $token = urldecode($check['_Token']['fields']);
366:         if (strpos($token, ':')) {
367:             list($token, ) = explode(':', $token, 2);
368:         }
369: 
370:         return $token;
371:     }
372: 
373:     /**
374:      * Return hash parts for the Token generation
375:      *
376:      * @param \Cake\Controller\Controller $controller Instantiating controller
377:      * @return array
378:      */
379:     protected function _hashParts(Controller $controller)
380:     {
381:         $request = $controller->getRequest();
382: 
383:         // Start the session to ensure we get the correct session id.
384:         $session = $request->getSession();
385:         $session->start();
386: 
387:         $data = $request->getData();
388:         $fieldList = $this->_fieldsList($data);
389:         $unlocked = $this->_sortedUnlocked($data);
390: 
391:         return [
392:             Router::url($request->getRequestTarget()),
393:             serialize($fieldList),
394:             $unlocked,
395:             $session->id()
396:         ];
397:     }
398: 
399:     /**
400:      * Return the fields list for the hash calculation
401:      *
402:      * @param array $check Data array
403:      * @return array
404:      */
405:     protected function _fieldsList(array $check)
406:     {
407:         $locked = '';
408:         $token = urldecode($check['_Token']['fields']);
409:         $unlocked = $this->_unlocked($check);
410: 
411:         if (strpos($token, ':')) {
412:             list($token, $locked) = explode(':', $token, 2);
413:         }
414:         unset($check['_Token'], $check['_csrfToken']);
415: 
416:         $locked = explode('|', $locked);
417:         $unlocked = explode('|', $unlocked);
418: 
419:         $fields = Hash::flatten($check);
420:         $fieldList = array_keys($fields);
421:         $multi = $lockedFields = [];
422:         $isUnlocked = false;
423: 
424:         foreach ($fieldList as $i => $key) {
425:             if (preg_match('/(\.\d+){1,10}$/', $key)) {
426:                 $multi[$i] = preg_replace('/(\.\d+){1,10}$/', '', $key);
427:                 unset($fieldList[$i]);
428:             } else {
429:                 $fieldList[$i] = (string)$key;
430:             }
431:         }
432:         if (!empty($multi)) {
433:             $fieldList += array_unique($multi);
434:         }
435: 
436:         $unlockedFields = array_unique(
437:             array_merge((array)$this->getConfig('disabledFields'), (array)$this->_config['unlockedFields'], $unlocked)
438:         );
439: 
440:         foreach ($fieldList as $i => $key) {
441:             $isLocked = (is_array($locked) && in_array($key, $locked));
442: 
443:             if (!empty($unlockedFields)) {
444:                 foreach ($unlockedFields as $off) {
445:                     $off = explode('.', $off);
446:                     $field = array_values(array_intersect(explode('.', $key), $off));
447:                     $isUnlocked = ($field === $off);
448:                     if ($isUnlocked) {
449:                         break;
450:                     }
451:                 }
452:             }
453: 
454:             if ($isUnlocked || $isLocked) {
455:                 unset($fieldList[$i]);
456:                 if ($isLocked) {
457:                     $lockedFields[$key] = $fields[$key];
458:                 }
459:             }
460:         }
461:         sort($fieldList, SORT_STRING);
462:         ksort($lockedFields, SORT_STRING);
463:         $fieldList += $lockedFields;
464: 
465:         return $fieldList;
466:     }
467: 
468:     /**
469:      * Get the unlocked string
470:      *
471:      * @param array $data Data array
472:      * @return string
473:      */
474:     protected function _unlocked(array $data)
475:     {
476:         return urldecode($data['_Token']['unlocked']);
477:     }
478: 
479:     /**
480:      * Get the sorted unlocked string
481:      *
482:      * @param array $data Data array
483:      * @return string
484:      */
485:     protected function _sortedUnlocked($data)
486:     {
487:         $unlocked = $this->_unlocked($data);
488:         $unlocked = explode('|', $unlocked);
489:         sort($unlocked, SORT_STRING);
490: 
491:         return implode('|', $unlocked);
492:     }
493: 
494:     /**
495:      * Create a message for humans to understand why Security token is not matching
496:      *
497:      * @param \Cake\Controller\Controller $controller Instantiating controller
498:      * @param array $hashParts Elements used to generate the Token hash
499:      * @return string Message explaining why the tokens are not matching
500:      */
501:     protected function _debugPostTokenNotMatching(Controller $controller, $hashParts)
502:     {
503:         $messages = [];
504:         $expectedParts = json_decode(urldecode($controller->getRequest()->getData('_Token.debug')), true);
505:         if (!is_array($expectedParts) || count($expectedParts) !== 3) {
506:             return 'Invalid security debug token.';
507:         }
508:         $expectedUrl = Hash::get($expectedParts, 0);
509:         $url = Hash::get($hashParts, 0);
510:         if ($expectedUrl !== $url) {
511:             $messages[] = sprintf('URL mismatch in POST data (expected \'%s\' but found \'%s\')', $expectedUrl, $url);
512:         }
513:         $expectedFields = Hash::get($expectedParts, 1);
514:         $dataFields = Hash::get($hashParts, 1);
515:         if ($dataFields) {
516:             $dataFields = unserialize($dataFields);
517:         }
518:         $fieldsMessages = $this->_debugCheckFields(
519:             $dataFields,
520:             $expectedFields,
521:             'Unexpected field \'%s\' in POST data',
522:             'Tampered field \'%s\' in POST data (expected value \'%s\' but found \'%s\')',
523:             'Missing field \'%s\' in POST data'
524:         );
525:         $expectedUnlockedFields = Hash::get($expectedParts, 2);
526:         $dataUnlockedFields = Hash::get($hashParts, 2) ?: null;
527:         if ($dataUnlockedFields) {
528:             $dataUnlockedFields = explode('|', $dataUnlockedFields);
529:         }
530:         $unlockFieldsMessages = $this->_debugCheckFields(
531:             (array)$dataUnlockedFields,
532:             $expectedUnlockedFields,
533:             'Unexpected unlocked field \'%s\' in POST data',
534:             null,
535:             'Missing unlocked field: \'%s\''
536:         );
537: 
538:         $messages = array_merge($messages, $fieldsMessages, $unlockFieldsMessages);
539: 
540:         return implode(', ', $messages);
541:     }
542: 
543:     /**
544:      * Iterates data array to check against expected
545:      *
546:      * @param array $dataFields Fields array, containing the POST data fields
547:      * @param array $expectedFields Fields array, containing the expected fields we should have in POST
548:      * @param string $intKeyMessage Message string if unexpected found in data fields indexed by int (not protected)
549:      * @param string $stringKeyMessage Message string if tampered found in data fields indexed by string (protected)
550:      * @param string $missingMessage Message string if missing field
551:      * @return array Messages
552:      */
553:     protected function _debugCheckFields($dataFields, $expectedFields = [], $intKeyMessage = '', $stringKeyMessage = '', $missingMessage = '')
554:     {
555:         $messages = $this->_matchExistingFields($dataFields, $expectedFields, $intKeyMessage, $stringKeyMessage);
556:         $expectedFieldsMessage = $this->_debugExpectedFields($expectedFields, $missingMessage);
557:         if ($expectedFieldsMessage !== null) {
558:             $messages[] = $expectedFieldsMessage;
559:         }
560: 
561:         return $messages;
562:     }
563: 
564:     /**
565:      * Manually add form tampering prevention token information into the provided
566:      * request object.
567:      *
568:      * @param \Cake\Http\ServerRequest $request The request object to add into.
569:      * @return \Cake\Http\ServerRequest The modified request.
570:      */
571:     public function generateToken(ServerRequest $request)
572:     {
573:         if ($request->is('requested')) {
574:             if ($this->session->check('_Token')) {
575:                 $request = $request->withParam('_Token', $this->session->read('_Token'));
576:             }
577: 
578:             return $request;
579:         }
580:         $token = [
581:             'allowedControllers' => $this->_config['allowedControllers'],
582:             'allowedActions' => $this->_config['allowedActions'],
583:             'unlockedFields' => $this->_config['unlockedFields'],
584:         ];
585: 
586:         $this->session->write('_Token', $token);
587: 
588:         return $request->withParam('_Token', [
589:             'unlockedFields' => $token['unlockedFields']
590:         ]);
591:     }
592: 
593:     /**
594:      * Calls a controller callback method
595:      *
596:      * @param \Cake\Controller\Controller $controller Instantiating controller
597:      * @param string $method Method to execute
598:      * @param array $params Parameters to send to method
599:      * @return mixed Controller callback method's response
600:      * @throws \Cake\Http\Exception\BadRequestException When a the blackholeCallback is not callable.
601:      */
602:     protected function _callback(Controller $controller, $method, $params = [])
603:     {
604:         if (!is_callable([$controller, $method])) {
605:             throw new BadRequestException('The request has been black-holed');
606:         }
607: 
608:         return call_user_func_array([&$controller, $method], empty($params) ? null : $params);
609:     }
610: 
611:     /**
612:      * Generate array of messages for the existing fields in POST data, matching dataFields in $expectedFields
613:      * will be unset
614:      *
615:      * @param array $dataFields Fields array, containing the POST data fields
616:      * @param array $expectedFields Fields array, containing the expected fields we should have in POST
617:      * @param string $intKeyMessage Message string if unexpected found in data fields indexed by int (not protected)
618:      * @param string $stringKeyMessage Message string if tampered found in data fields indexed by string (protected)
619:      * @return array Error messages
620:      */
621:     protected function _matchExistingFields($dataFields, &$expectedFields, $intKeyMessage, $stringKeyMessage)
622:     {
623:         $messages = [];
624:         foreach ((array)$dataFields as $key => $value) {
625:             if (is_int($key)) {
626:                 $foundKey = array_search($value, (array)$expectedFields);
627:                 if ($foundKey === false) {
628:                     $messages[] = sprintf($intKeyMessage, $value);
629:                 } else {
630:                     unset($expectedFields[$foundKey]);
631:                 }
632:             } elseif (is_string($key)) {
633:                 if (isset($expectedFields[$key]) && $value !== $expectedFields[$key]) {
634:                     $messages[] = sprintf($stringKeyMessage, $key, $expectedFields[$key], $value);
635:                 }
636:                 unset($expectedFields[$key]);
637:             }
638:         }
639: 
640:         return $messages;
641:     }
642: 
643:     /**
644:      * Generate debug message for the expected fields
645:      *
646:      * @param array $expectedFields Expected fields
647:      * @param string $missingMessage Message template
648:      * @return string|null Error message about expected fields
649:      */
650:     protected function _debugExpectedFields($expectedFields = [], $missingMessage = '')
651:     {
652:         if (count($expectedFields) === 0) {
653:             return null;
654:         }
655: 
656:         $expectedFieldNames = [];
657:         foreach ((array)$expectedFields as $key => $expectedField) {
658:             if (is_int($key)) {
659:                 $expectedFieldNames[] = $expectedField;
660:             } else {
661:                 $expectedFieldNames[] = $key;
662:             }
663:         }
664: 
665:         return sprintf($missingMessage, implode(', ', $expectedFieldNames));
666:     }
667: }
668: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs