FormDataPart.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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\Mime\Part\Multipart;
  11. use Symfony\Component\Mime\Exception\InvalidArgumentException;
  12. use Symfony\Component\Mime\Part\AbstractMultipartPart;
  13. use Symfony\Component\Mime\Part\DataPart;
  14. use Symfony\Component\Mime\Part\TextPart;
  15. /**
  16. * Implements RFC 7578.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. */
  20. final class FormDataPart extends AbstractMultipartPart
  21. {
  22. private $fields = [];
  23. /**
  24. * @param array<string|array|DataPart> $fields
  25. */
  26. public function __construct(array $fields = [])
  27. {
  28. parent::__construct();
  29. foreach ($fields as $name => $value) {
  30. if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) {
  31. throw new InvalidArgumentException(sprintf('A form field value can only be a string, an array, or an instance of TextPart ("%s" given).', \is_object($value) ? \get_class($value) : \gettype($value)));
  32. }
  33. $this->fields[$name] = $value;
  34. }
  35. // HTTP does not support \r\n in header values
  36. $this->getHeaders()->setMaxLineLength(\PHP_INT_MAX);
  37. }
  38. public function getMediaSubtype(): string
  39. {
  40. return 'form-data';
  41. }
  42. public function getParts(): array
  43. {
  44. return $this->prepareFields($this->fields);
  45. }
  46. private function prepareFields(array $fields): array
  47. {
  48. $values = [];
  49. $prepare = function ($item, $key, $root = null) use (&$values, &$prepare) {
  50. $fieldName = $root ? sprintf('%s[%s]', $root, $key) : $key;
  51. if (\is_array($item)) {
  52. array_walk($item, $prepare, $fieldName);
  53. return;
  54. }
  55. $values[] = $this->preparePart($fieldName, $item);
  56. };
  57. array_walk($fields, $prepare);
  58. return $values;
  59. }
  60. private function preparePart(string $name, $value): TextPart
  61. {
  62. if (\is_string($value)) {
  63. return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit'));
  64. }
  65. return $this->configurePart($name, $value);
  66. }
  67. private function configurePart(string $name, TextPart $part): TextPart
  68. {
  69. static $r;
  70. if (null === $r) {
  71. $r = new \ReflectionProperty(TextPart::class, 'encoding');
  72. $r->setAccessible(true);
  73. }
  74. $part->setDisposition('form-data');
  75. $part->setName($name);
  76. // HTTP does not support \r\n in header values
  77. $part->getHeaders()->setMaxLineLength(\PHP_INT_MAX);
  78. $r->setValue($part, '8bit');
  79. return $part;
  80. }
  81. }