Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\HttpFoundation; Chris@0: Chris@0: use Symfony\Component\HttpFoundation\File\UploadedFile; Chris@0: Chris@0: /** Chris@0: * FileBag is a container for uploaded files. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: * @author Bulat Shakirzyanov Chris@0: */ Chris@0: class FileBag extends ParameterBag Chris@0: { Chris@17: private static $fileKeys = ['error', 'name', 'size', 'tmp_name', 'type']; Chris@0: Chris@0: /** Chris@0: * @param array $parameters An array of HTTP files Chris@0: */ Chris@17: public function __construct(array $parameters = []) Chris@0: { Chris@0: $this->replace($parameters); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: public function replace(array $files = []) Chris@0: { Chris@17: $this->parameters = []; Chris@0: $this->add($files); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function set($key, $value) Chris@0: { Chris@17: if (!\is_array($value) && !$value instanceof UploadedFile) { Chris@0: throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.'); Chris@0: } Chris@0: Chris@0: parent::set($key, $this->convertFileInformation($value)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: public function add(array $files = []) Chris@0: { Chris@0: foreach ($files as $key => $file) { Chris@0: $this->set($key, $file); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Converts uploaded files to UploadedFile instances. Chris@0: * Chris@0: * @param array|UploadedFile $file A (multi-dimensional) array of uploaded file information Chris@0: * Chris@14: * @return UploadedFile[]|UploadedFile|null A (multi-dimensional) array of UploadedFile instances Chris@0: */ Chris@0: protected function convertFileInformation($file) Chris@0: { Chris@0: if ($file instanceof UploadedFile) { Chris@0: return $file; Chris@0: } Chris@0: Chris@0: $file = $this->fixPhpFilesArray($file); Chris@17: if (\is_array($file)) { Chris@0: $keys = array_keys($file); Chris@0: sort($keys); Chris@0: Chris@0: if ($keys == self::$fileKeys) { Chris@0: if (UPLOAD_ERR_NO_FILE == $file['error']) { Chris@0: $file = null; Chris@0: } else { Chris@0: $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']); Chris@0: } Chris@0: } else { Chris@17: $file = array_map([$this, 'convertFileInformation'], $file); Chris@14: if (array_keys($keys) === $keys) { Chris@14: $file = array_filter($file); Chris@14: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $file; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Fixes a malformed PHP $_FILES array. Chris@0: * Chris@0: * PHP has a bug that the format of the $_FILES array differs, depending on Chris@0: * whether the uploaded file fields had normal field names or array-like Chris@0: * field names ("normal" vs. "parent[child]"). Chris@0: * Chris@0: * This method fixes the array to look like the "normal" $_FILES array. Chris@0: * Chris@0: * It's safe to pass an already converted array, in which case this method Chris@0: * just returns the original array unmodified. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: protected function fixPhpFilesArray($data) Chris@0: { Chris@17: if (!\is_array($data)) { Chris@0: return $data; Chris@0: } Chris@0: Chris@0: $keys = array_keys($data); Chris@0: sort($keys); Chris@0: Chris@17: if (self::$fileKeys != $keys || !isset($data['name']) || !\is_array($data['name'])) { Chris@0: return $data; Chris@0: } Chris@0: Chris@0: $files = $data; Chris@0: foreach (self::$fileKeys as $k) { Chris@0: unset($files[$k]); Chris@0: } Chris@0: Chris@0: foreach ($data['name'] as $key => $name) { Chris@17: $files[$key] = $this->fixPhpFilesArray([ Chris@0: 'error' => $data['error'][$key], Chris@0: 'name' => $name, Chris@0: 'type' => $data['type'][$key], Chris@0: 'tmp_name' => $data['tmp_name'][$key], Chris@0: 'size' => $data['size'][$key], Chris@17: ]); Chris@0: } Chris@0: Chris@0: return $files; Chris@0: } Chris@0: }