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.7 Red Velvet API

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