FileBag.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.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\HttpFoundation;
  11. use Symfony\Component\HttpFoundation\File\UploadedFile;
  12. /**
  13. * FileBag is a container for HTTP headers.
  14. *
  15. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  16. * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
  17. */
  18. class FileBag extends ParameterBag
  19. {
  20. private $fileKeys = array('error', 'name', 'size', 'tmp_name', 'type');
  21. /**
  22. * (non-PHPdoc)
  23. * @see Symfony\Component\HttpFoundation\ParameterBag::replace()
  24. */
  25. public function replace(array $files = array())
  26. {
  27. $this->parameters = array();
  28. $this->add($files);
  29. }
  30. /**
  31. * (non-PHPdoc)
  32. * @see Symfony\Component\HttpFoundation\ParameterBag::set()
  33. */
  34. public function set($key, $value)
  35. {
  36. if (is_array($value) || $value instanceof UploadedFile) {
  37. parent::set($key, $this->convertFileInformation($value));
  38. }
  39. }
  40. /**
  41. * (non-PHPdoc)
  42. * @see Symfony\Component\HttpFoundation\ParameterBag::add()
  43. */
  44. public function add(array $files = array())
  45. {
  46. foreach ($files as $key => $file) {
  47. $this->set($key, $file);
  48. }
  49. }
  50. /**
  51. * Converts uploaded files to UploadedFile instances.
  52. *
  53. * @param array|UploadedFile $file A (multi-dimensional) array of uploaded file information
  54. *
  55. * @return array A (multi-dimensional) array of UploadedFile instances
  56. */
  57. protected function convertFileInformation($file)
  58. {
  59. if ($file instanceof UploadedFile) {
  60. return $file;
  61. }
  62. $file = $this->fixPhpFilesArray($file);
  63. if (is_array($file)) {
  64. $keys = array_keys($file);
  65. sort($keys);
  66. if ($keys == $this->fileKeys) {
  67. $file['error'] = (int) $file['error'];
  68. }
  69. if ($keys != $this->fileKeys) {
  70. $file = array_map(array($this, 'convertFileInformation'), $file);
  71. } else
  72. if ($file['error'] === UPLOAD_ERR_NO_FILE) {
  73. $file = null;
  74. } else {
  75. $file = new UploadedFile($file['tmp_name'], $file['name'],
  76. $file['type'], $file['size'], $file['error']);
  77. }
  78. }
  79. return $file;
  80. }
  81. /**
  82. * Fixes a malformed PHP $_FILES array.
  83. *
  84. * PHP has a bug that the format of the $_FILES array differs, depending on
  85. * whether the uploaded file fields had normal field names or array-like
  86. * field names ("normal" vs. "parent[child]").
  87. *
  88. * This method fixes the array to look like the "normal" $_FILES array.
  89. *
  90. * It's safe to pass an already converted array, in which case this method
  91. * just returns the original array unmodified.
  92. *
  93. * @param array $data
  94. * @return array
  95. */
  96. protected function fixPhpFilesArray($data)
  97. {
  98. if (! is_array($data)) {
  99. return $data;
  100. }
  101. $keys = array_keys($data);
  102. sort($keys);
  103. if ($this->fileKeys != $keys || ! isset($data['name']) ||
  104. ! is_array($data['name'])) {
  105. return $data;
  106. }
  107. $files = $data;
  108. foreach ($this->fileKeys as $k) {
  109. unset($files[$k]);
  110. }
  111. foreach (array_keys($data['name']) as $key) {
  112. $files[$key] = $this->fixPhpFilesArray(array(
  113. 'error' => $data['error'][$key],
  114. 'name' => $data['name'][$key], 'type' => $data['type'][$key],
  115. 'tmp_name' => $data['tmp_name'][$key],
  116. 'size' => $data['size'][$key]
  117. ));
  118. }
  119. return $files;
  120. }
  121. }