これがループしたい入力です
_Main photo: <input type="file" name="image[]" />
Side photo 1: <input type="file" name="image[]" />
Side photo 2: <input type="file" name="image[]" />
Side photo 3: <input type="file" name="image[]" />
_
奇妙なことがいくつか起こりました。何もアップロードせずにcount($_FILES['image'])
を使用すると、その関数がエコーされ、値5が返されます。その配列には要素がないはずです。最初は4つのファイルしかないのに、追加の入力が1つあるのはなぜですか?
今度は実際にループするので、foreachループを使用してみますが、機能しません。
_foreach($_FILES['image'] as $files){echo $files['name']; }
_
何も思いつきませんでした。最終的に私がやりたかったのは、すべての画像をループし、正しい形式、サイズであることを確認し、それぞれの名前を変更することです。しかし、この単純なforeach()ループは、何とか$ _FILES配列をループすることさえできず、何もアップロードしなかったときに配列に5つの要素があると言うと、count()がさらに混乱したことを示しています。
サンプルフォームは問題なく機能するはずです。フィールド名に配列構造を使用する場合、_$_FILES
_スーパーグローバルの構造が実際のものとは異なることを期待しているだけです。
この多次元配列の構造は次のとおりです。
_$_FILES[fieldname] => array(
[name] => array( /* these arrays are the size you expect */ )
[type] => array( /* these arrays are the size you expect */ )
[tmp_name] => array( /* these arrays are the size you expect */ )
[error] => array( /* these arrays are the size you expect */ )
[size] => array( /* these arrays are the size you expect */ )
);
_
そのため、count( $_FILES[ "fieldname" ] )
は_5
_を生成します。
しかし、より深い次元をカウントしても、期待した結果が得られません。たとえば、count( $_FILES[ "fieldname" ][ "tmp_name" ] )
を使用してフィールドをカウントすると、実際にアップロードされたファイルの数ではなく、常にファイルフィールドの数になります。要素をループして、特定のファイルフィールドにアップロードされたものがあるかどうかを判断する必要があります。
[〜#〜]編集[〜#〜]
したがって、フィールドをループするには、次のようなことを行います。
_// !empty( $_FILES ) is an extra safety precaution
// in case the form's enctype="multipart/form-data" attribute is missing
// or in case your form doesn't have any file field elements
if( strtolower( $_SERVER[ 'REQUEST_METHOD' ] ) == 'post' && !empty( $_FILES ) )
{
foreach( $_FILES[ 'image' ][ 'tmp_name' ] as $index => $tmpName )
{
if( !empty( $_FILES[ 'image' ][ 'error' ][ $index ] ) )
{
// some error occured with the file in index $index
// yield an error here
return false; // return false also immediately perhaps??
}
/*
edit: the following is not necessary actually as it is now
defined in the foreach statement ($index => $tmpName)
// extract the temporary location
$tmpName = $_FILES[ 'image' ][ 'tmp_name' ][ $index ];
*/
// check whether it's not empty, and whether it indeed is an uploaded file
if( !empty( $tmpName ) && is_uploaded_file( $tmpName ) )
{
// the path to the actual uploaded file is in $_FILES[ 'image' ][ 'tmp_name' ][ $index ]
// do something with it:
move_uploaded_file( $tmpName, $someDestinationPath ); // move to new location perhaps?
}
}
}
_
詳細は the docs を参照してください。
このようにフィールドの名前を変更するだけです
Main photo: <input type="file" name="image1" />
Side photo 1: <input type="file" name="image2" />
Side photo 2: <input type="file" name="image3" />
Side photo 3: <input type="file" name="image4" />
そして、あなたはそれを通常の方法で繰り返すことができるでしょう:
foreach($_FILES as $file){
echo $file['name'];
}
$ _FILES ['files']をより期待される構造に再構築するための短い関数。
function restructureFilesArray($files)
{
$output = [];
foreach ($files as $attrName => $valuesArray) {
foreach ($valuesArray as $key => $value) {
$output[$key][$attrName] = $value;
}
}
return $output;
}
任意の深さの$ _FILES配列で機能するソリューションを思いつきました。簡単な説明として、これを行うアルゴリズムが必要なもの:
For each subtree in the file tree that's more than one item deep:
For each leaf of the subtree:
$leaf[a][b][c] ... [y][z] -> $result[z][a][b][c] ... [y]
実際に機能するコードを以下に示します。
function sane_file_array($files) {
$result = array();
$name = array();
$type = array();
$tmp_name = array();
$error = array();
$size = array();
foreach($files as $field => $data) {
foreach($data as $key => $val) {
$result[$field] = array();
if(!is_array($val)) {
$result[$field] = $data;
} else {
$res = array();
files_flip($res, array(), $data);
$result[$field] += $res;
}
}
}
return $result;
}
function array_merge_recursive2($paArray1, $paArray2) {
if (!is_array($paArray1) or !is_array($paArray2)) { return $paArray2; }
foreach ($paArray2 AS $sKey2 => $sValue2) {
$paArray1[$sKey2] = array_merge_recursive2(@$paArray1[$sKey2], $sValue2);
}
return $paArray1;
}
function files_flip(&$result, $keys, $value) {
if(is_array($value)) {
foreach($value as $k => $v) {
$newkeys = $keys;
array_Push($newkeys, $k);
files_flip($result, $newkeys, $v);
}
} else {
$res = $value;
// Move the innermost key to the outer spot
$first = array_shift($keys);
array_Push($keys, $first);
foreach(array_reverse($keys) as $k) {
// You might think we'd say $res[$k] = $res, but $res starts out not as an array
$res = array($k => $res);
}
$result = array_merge_recursive2($result, $res);
}
}
$ _FILESでsane_files_arrayを呼び出すだけで、$ _ FILES配列の深さに関係なく、問題ありません。 $ _FILES配列のフォーマットはまったくばかげているので、これは実際には言語自体の一部である必要があります。
多分:
Main photo: <input type="file" name="image1" />
Side photo 1: <input type="file" name="image2" />
Side photo 2: <input type="file" name="image3" />
Side photo 3: <input type="file" name="image4" />
$i=1;
while (isset($_FILES['image'.$i])) {
print_r($_FILES['image'.$i]);
$i++;
}
特定のファイルフィールドをループする必要がある場合。
PHPが$ _FILESの処理方法を選択すると、開発者の多くの時間が無駄になります。 @Lendrickの回答に基づいて、ここに同様のOOアプローチがあります。
/**
* @brief get the POSTed files in a more usable format
Works on the following methods:
<form method="post" action="/" name="" enctype="multipart/form-data">
<input type="file" name="photo1" />
<input type="file" name="photo2[]" />
<input type="file" name="photo2[]" />
<input type="file" name="photo3[]" multiple />
* @return Array
* @todo
* @see http://stackoverflow.com/questions/5444827/how-do-you-loop-through-files-array
*/
public static function GetPostedFiles()
{
/* group the information together like this example
Array
(
[attachments] => Array
(
[0] => Array
(
[name] => car.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpe1fdEB
[error] => 0
[size] => 2345276
)
)
[jimmy] => Array
(
[0] => Array
(
[name] => 1.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpx1HXrr
[error] => 0
[size] => 221041
)
[1] => Array
(
[name] => 2 ' .jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpQ1clPh
[error] => 0
[size] => 47634
)
)
)
*/
$Result = array();
$Name = array();
$Type = array();
$TmpName = array();
$Error = array();
$Size = array();
foreach($_FILES as $Field => $Data)
{
foreach($Data as $Key => $Val)
{
$Result[$Field] = array();
if(!is_array($Val))
$Result[$Field] = $Data;
else
{
$Res = array();
self::GPF_FilesFlip($Res, array(), $Data);
$Result[$Field] += $Res;
}
}
}
return $Result;
}
private static function GPF_ArrayMergeRecursive($PaArray1, $PaArray2)
{
// helper method for GetPostedFiles
if (!is_array($PaArray1) or !is_array($PaArray2))
return $PaArray2;
foreach ($PaArray2 AS $SKey2 => $SValue2)
$PaArray1[$SKey2] = self::GPF_ArrayMergeRecursive(@$PaArray1[$SKey2], $SValue2);
return $PaArray1;
}
private static function GPF_FilesFlip(&$Result, $Keys, $Value)
{
// helper method for GetPostedFiles
if(is_array($Value))
{
foreach($Value as $K => $V)
{
$NewKeys = $Keys;
array_Push($NewKeys, $K);
self::GPF_FilesFlip($Result, $NewKeys, $V);
}
}
else
{
$Res = $Value;
// move the innermost key to the outer spot
$First = array_shift($Keys);
array_Push($Keys, $First);
foreach(array_reverse($Keys) as $K)
$Res = array($K => $Res); // you might think we'd say $Res[$K] = $Res, but $Res starts out not as an array
$Result = self::GPF_ArrayMergeRecursive($Result, $Res);
}
}
私はこの答えのためにゲームにかなり遅れていますが、PHP files arrayを何度も処理する問題を解決するのに飽きたので、composerパッケージなので、もう二度とする必要はありません。
インストール tvanc/files-array-organizer
composer require tvanc/files-array-organizer
パス $_FILES
を追加すると、期待どおりに構造化された配列が返されます。
<?php
use tvanc\FilesArrayOrganizer\FilesArrayOrganizer;
require 'vendor/autoload.php';
if ($_FILES) {
$organizedFiles = FilesArrayOrganizer::organize($_FILES);
// Now you can foreach over your files
foreach($organizedFiles['image'] as $file){
echo $file['name'];
}
}
?>
Main photo: <input type="file" name="image[]" />
Side photo 1: <input type="file" name="image[]" />
Side photo 2: <input type="file" name="image[]" />
Side photo 3: <input type="file" name="image[]" />
私はこのジレンマとほぼ一週間苦労しています!ネットで見つけたものは何の助けにもなりません。私は何をすべきかを知っていましたが、$ _ FILES配列を適切にループする方法を理解することができませんでした。
ただし、投稿されたスクリプトでは、私には適切に機能しなかったため、いくつか変更を加えました。ファイルが選択されたかどうかを判断できるようにしたいので、「if(!empty($ _FILES ['image'] ['error'] [$ index]))」という行を「if(! empty($ _FILES ['image'] ['size'] [$ index])) "そして" return false; "の代わりに、サイズを変数に入れます:" $ Size = $ _FILES ['upload' ] ['size'] [$ index]; "
このようにして、$ Size変数がゼロより大きいかどうかを確認できます。そうであれば、ファイルが選択されていたので、ファイル数のカウントを続行して実際のアップロードを行うことができました。受け入れられた回答では、「return false;」の後に「不要な」スクリプトを使用しませんでした。これが誰かを助けることを願っています。
:P/MacD