DoTrustedCallbackTrait.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. namespace Drupal\Core\Security;
  3. /**
  4. * Ensures that TrustedCallbackInterface can be enforced for callback methods.
  5. *
  6. * @see \Drupal\Core\Security\TrustedCallbackInterface
  7. */
  8. trait DoTrustedCallbackTrait {
  9. /**
  10. * Performs a callback.
  11. *
  12. * If the callback is trusted the callback will occur. Trusted callbacks must
  13. * be methods of a class that implements
  14. * \Drupal\Core\Security\TrustedCallbackInterface or $extra_trusted_interface
  15. * or be an anonymous function. If the callback is not trusted then whether or
  16. * not the callback is called and what type of error is thrown depends on
  17. * $error_type. To provide time for dependent code to use trusted callbacks
  18. * use TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION and then at a
  19. * later date change this to TrustedCallbackInterface::THROW_EXCEPTION.
  20. *
  21. * @param callable $callback
  22. * The callback to call. Note that callbacks which are objects and use the
  23. * magic method __invoke() are not supported.
  24. * @param array $args
  25. * The arguments to pass the callback.
  26. * @param $message
  27. * The error message if the callback is not trusted. If the message contains
  28. * "%s" it will be replaced in with the resolved callback.
  29. * @param string $error_type
  30. * (optional) The type of error to trigger. One of:
  31. * - TrustedCallbackInterface::THROW_EXCEPTION
  32. * - TrustedCallbackInterface::TRIGGER_WARNING
  33. * - TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION
  34. * Defaults to TrustedCallbackInterface::THROW_EXCEPTION.
  35. * @param string $extra_trusted_interface
  36. * (optional) An additional interface that if implemented by the callback
  37. * object means any public methods on that object are trusted.
  38. *
  39. * @return mixed
  40. * The callback's return value.
  41. *
  42. * @throws \Drupal\Core\Security\UntrustedCallbackException
  43. * Exception thrown if the callback is not trusted and $error_type equals
  44. * TrustedCallbackInterface::THROW_EXCEPTION.
  45. *
  46. * @see \Drupal\Core\Security\TrustedCallbackInterface
  47. */
  48. public function doTrustedCallback(callable $callback, array $args, $message, $error_type = TrustedCallbackInterface::THROW_EXCEPTION, $extra_trusted_interface = NULL) {
  49. $object_or_classname = $callback;
  50. $safe_callback = FALSE;
  51. if (is_array($callback)) {
  52. list($object_or_classname, $method_name) = $callback;
  53. }
  54. elseif (is_string($callback) && strpos($callback, '::') !== FALSE) {
  55. list($object_or_classname, $method_name) = explode('::', $callback, 2);
  56. }
  57. if (isset($method_name)) {
  58. if ($extra_trusted_interface && is_subclass_of($object_or_classname, $extra_trusted_interface)) {
  59. $safe_callback = TRUE;
  60. }
  61. elseif (is_subclass_of($object_or_classname, TrustedCallbackInterface::class)) {
  62. if (is_object($object_or_classname)) {
  63. $methods = $object_or_classname->trustedCallbacks();
  64. }
  65. else {
  66. $methods = call_user_func($object_or_classname . '::trustedCallbacks');
  67. }
  68. $safe_callback = in_array($method_name, $methods, TRUE);
  69. }
  70. }
  71. elseif ($callback instanceof \Closure) {
  72. $safe_callback = TRUE;
  73. }
  74. if (!$safe_callback) {
  75. $description = $object_or_classname;
  76. if (is_object($description)) {
  77. $description = get_class($description);
  78. }
  79. if (isset($method_name)) {
  80. $description .= '::' . $method_name;
  81. }
  82. $message = sprintf($message, $description);
  83. if ($error_type === TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION) {
  84. @trigger_error($message, E_USER_DEPRECATED);
  85. }
  86. elseif ($error_type === TrustedCallbackInterface::TRIGGER_WARNING) {
  87. trigger_error($message, E_USER_WARNING);
  88. }
  89. else {
  90. throw new UntrustedCallbackException($message);
  91. }
  92. }
  93. return call_user_func_array($callback, $args);
  94. }
  95. }