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