PhpSerializer.php 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Messenger\Transport\Serialization;
  11. use Symfony\Component\Messenger\Envelope;
  12. use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
  13. use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
  14. /**
  15. * @author Ryan Weaver<ryan@symfonycasts.com>
  16. */
  17. class PhpSerializer implements SerializerInterface
  18. {
  19. /**
  20. * {@inheritdoc}
  21. */
  22. public function decode(array $encodedEnvelope): Envelope
  23. {
  24. if (empty($encodedEnvelope['body'])) {
  25. throw new MessageDecodingFailedException('Encoded envelope should have at least a "body".');
  26. }
  27. if (false === strpos($encodedEnvelope['body'], '}', -1)) {
  28. $encodedEnvelope['body'] = base64_decode($encodedEnvelope['body']);
  29. }
  30. $serializeEnvelope = stripslashes($encodedEnvelope['body']);
  31. return $this->safelyUnserialize($serializeEnvelope);
  32. }
  33. /**
  34. * {@inheritdoc}
  35. */
  36. public function encode(Envelope $envelope): array
  37. {
  38. $envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class);
  39. $body = addslashes(serialize($envelope));
  40. if (!preg_match('//u', $body)) {
  41. $body = base64_encode($body);
  42. }
  43. return [
  44. 'body' => $body,
  45. ];
  46. }
  47. private function safelyUnserialize(string $contents)
  48. {
  49. $signalingException = new MessageDecodingFailedException(sprintf('Could not decode message using PHP serialization: %s.', $contents));
  50. $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback');
  51. $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) {
  52. if (__FILE__ === $file) {
  53. throw $signalingException;
  54. }
  55. return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
  56. });
  57. try {
  58. $meta = unserialize($contents);
  59. } finally {
  60. restore_error_handler();
  61. ini_set('unserialize_callback_func', $prevUnserializeHandler);
  62. }
  63. return $meta;
  64. }
  65. /**
  66. * @internal
  67. */
  68. public static function handleUnserializeCallback($class)
  69. {
  70. throw new MessageDecodingFailedException(sprintf('Message class "%s" not found during decoding.', $class));
  71. }
  72. }