1<?php 2/** 3 * @see https://github.com/zendframework/zend-diactoros for the canonical source repository 4 * @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com) 5 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License 6 */ 7 8namespace Zend\Diactoros; 9 10use InvalidArgumentException; 11use Psr\Http\Message\UploadedFileInterface; 12 13use function is_array; 14 15/** 16 * Normalize uploaded files 17 * 18 * Transforms each value into an UploadedFile instance, and ensures that nested 19 * arrays are normalized. 20 * 21 * @param array $files 22 * @return UploadedFileInterface[] 23 * @throws InvalidArgumentException for unrecognized values 24 */ 25function normalizeUploadedFiles(array $files) 26{ 27 /** 28 * Traverse a nested tree of uploaded file specifications. 29 * 30 * @param string[]|array[] $tmpNameTree 31 * @param int[]|array[] $sizeTree 32 * @param int[]|array[] $errorTree 33 * @param string[]|array[]|null $nameTree 34 * @param string[]|array[]|null $typeTree 35 * @return UploadedFile[]|array[] 36 */ 37 $recursiveNormalize = function ( 38 array $tmpNameTree, 39 array $sizeTree, 40 array $errorTree, 41 array $nameTree = null, 42 array $typeTree = null 43 ) use (&$recursiveNormalize) { 44 $normalized = []; 45 foreach ($tmpNameTree as $key => $value) { 46 if (is_array($value)) { 47 // Traverse 48 $normalized[$key] = $recursiveNormalize( 49 $tmpNameTree[$key], 50 $sizeTree[$key], 51 $errorTree[$key], 52 isset($nameTree[$key]) ? $nameTree[$key] : null, 53 isset($typeTree[$key]) ? $typeTree[$key] : null 54 ); 55 continue; 56 } 57 $normalized[$key] = createUploadedFile([ 58 'tmp_name' => $tmpNameTree[$key], 59 'size' => $sizeTree[$key], 60 'error' => $errorTree[$key], 61 'name' => isset($nameTree[$key]) ? $nameTree[$key] : null, 62 'type' => isset($typeTree[$key]) ? $typeTree[$key] : null 63 ]); 64 } 65 return $normalized; 66 }; 67 68 /** 69 * Normalize an array of file specifications. 70 * 71 * Loops through all nested files (as determined by receiving an array to the 72 * `tmp_name` key of a `$_FILES` specification) and returns a normalized array 73 * of UploadedFile instances. 74 * 75 * This function normalizes a `$_FILES` array representing a nested set of 76 * uploaded files as produced by the php-fpm SAPI, CGI SAPI, or mod_php 77 * SAPI. 78 * 79 * @param array $files 80 * @return UploadedFile[] 81 */ 82 $normalizeUploadedFileSpecification = function (array $files = []) use (&$recursiveNormalize) { 83 if (! isset($files['tmp_name']) || ! is_array($files['tmp_name']) 84 || ! isset($files['size']) || ! is_array($files['size']) 85 || ! isset($files['error']) || ! is_array($files['error']) 86 ) { 87 throw new InvalidArgumentException(sprintf( 88 '$files provided to %s MUST contain each of the keys "tmp_name",' 89 . ' "size", and "error", with each represented as an array;' 90 . ' one or more were missing or non-array values', 91 __FUNCTION__ 92 )); 93 } 94 95 return $recursiveNormalize( 96 $files['tmp_name'], 97 $files['size'], 98 $files['error'], 99 isset($files['name']) ? $files['name'] : null, 100 isset($files['type']) ? $files['type'] : null 101 ); 102 }; 103 104 $normalized = []; 105 foreach ($files as $key => $value) { 106 if ($value instanceof UploadedFileInterface) { 107 $normalized[$key] = $value; 108 continue; 109 } 110 111 if (is_array($value) && isset($value['tmp_name']) && is_array($value['tmp_name'])) { 112 $normalized[$key] = $normalizeUploadedFileSpecification($value); 113 continue; 114 } 115 116 if (is_array($value) && isset($value['tmp_name'])) { 117 $normalized[$key] = createUploadedFile($value); 118 continue; 119 } 120 121 if (is_array($value)) { 122 $normalized[$key] = normalizeUploadedFiles($value); 123 continue; 124 } 125 126 throw new InvalidArgumentException('Invalid value in files specification'); 127 } 128 return $normalized; 129} 130