Skip to content
Advertisement

PHP Upload Multiple Images through Loop

I am trying to upload multiple images in a loop but for some reason it will create the directory, upload 1 file and create the MySQL record so I’m not sure why it only uploads 1 file even though when i’ve printed $i to see how many files have been counted it always counts the correct amount.

PHP

function generateRandomString($length = 25) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}
if (isset($_POST['newYoungSubmit'])) {

    $imageDirectory = "images/youngMembers";
    $newDirName = generateRandomString(20);
    $postDate = date("Y-m-d");
    $targetDir = $imageDirectory."/".$newDirName."/";

    if (!file_exists($targetDir)) {
        mkdir($targetDir, 0777, true);
    } else {
        $newDirName = generateRandomString(20);
        $targetDir = $imageDirectory."/".$newDirName."/";
    }

    // Count total files
    $fileCount = count($_FILES['new_young']['name']);
    // Iterate through the files
    for($i = 0; $i < $fileCount; $i++){
        $target_dir = $imageDirectory."/".$newDirName."/";
        $target_file = $target_dir . basename($_FILES["new_young"]["name"][$i]);
        $uploadOk = 1;
        $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
        // Check if image file is a actual image or fake image
        $check = getimagesize($_FILES["new_young"]["tmp_name"][$i]);
        if($check !== false) {
            //echo "File is an image - " . $check["mime"] . ".";
            $uploadOk = 1;
        } else {
            $errorTxt = "File is not an image.";
            $uploadOk = 0;
        }
        // Check if file already exists
        if (file_exists($target_file)) {
            $errorTxt =  "Sorry, file already exists.";
            $uploadOk = 0;
        }
        // Check file size
        // if ($_FILES["new_young"]["size"] > 500000) {
        //     $errorTxt =  "Sorry, your file is too large.";
        //     $uploadOk = 0;
        // }
        // Allow certain file formats
        if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
        && $imageFileType != "gif" ) {
            $errorTxt = "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
            $uploadOk = 0;
        }
        // Check if $uploadOk is set to 0 by an error
        $temp = explode(".", $_FILES["new_young"]["name"][$i]);
        $newfilename = round(microtime(true)) . '.' . end($temp);
        if ($uploadOk == 0) {
            
        // if everything is ok, try to upload file

        } else {
            if (move_uploaded_file($_FILES["new_young"]["tmp_name"][$i], $target_dir . $newfilename)) {
                //echo "The file ". basename( $_FILES["new_young"]["name"]). " has been uploaded.";
            } else {
                $errorTxt = "Sorry, there was an error uploading your file.";
            }
        }
    }

    $newYoungQuery = $conn->prepare("INSERT INTO youngMembers (youngTitle, youngImgDir, youngDesc) VALUES (?,?,?)");
    $newYoungQuery->execute([$_POST['youngTitle'], $targetDir, $_POST['youngDesc']]);
    $newYoungQuery = null;

    }

HTML

<form class="col s12" method="POST" action="" enctype="multipart/form-data">
    <div class="row">
        <div class="input-field col s12 m6">
            <input name="youngTitle" id="youngTitle" required type="text" class="validate">
            <label for="youngTitle">Title<span class="red-text">*</span></label>
        </div>
        <div class="file-field input-field col s12 m6">
            <div class="btn">
                <span>Image(s)</span>
                <input name="new_young[]" type="file" multiple="multiple">
            </div>
            <div class="file-path-wrapper">
                <input class="file-path validate" type="text">
            </div>
        </div>
    </div>
    <div class="row">
        <div class="input-field col s12 m12">
            <div class="input-field col s12 m12">
                <textarea id="youngDesc" name="youngDesc" class="materialize-textarea" data-length="4096"></textarea>
                <label for="youngDesc">Description</label>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col s12 m3 offset-m9 input-field">
            <input type="submit" class="white green-button-border black-text btn-large" name="newYoungSubmit">
        </div>
    </div>
</form>

I’ve uploaded the HTML form and the PHP script that is run when the form is submitted, as far as I’m aware my script will check if the form has been submitted, generate a random string which becomes the new directory name which after i’ve checked if it’s been created or not then if not the new directory is created and then i run a loop to loop through and upload all selected images to that directory and finally I upload the data to the MySQL table.

Advertisement

Answer

The problem, I believe having gone through the code properly and tested it lies with the fact that the files are being saved with a new name and that new name is generated using:

$newfilename = round( microtime(true) ) . '.' . end($temp);

When I tested this on a 3 file upload I observed the following when I added some debug statements.

..OK
1630745144.jpg - OK

..OK
1630745144.jpg - OK

..OK
1630745144.jpg - OK

All three were assigned the same name and thus only the last appears to be uploaded as the other two were overwritten.

The debug mentioned was:

$newfilename = round( microtime(true) ) . '.' . end($temp);
if ($uploadOk == 0) {
    echo $errorTxt;
} else {
    
    if (move_uploaded_file($_FILES["new_young"]["tmp_name"][$i], $target_dir . $newfilename)) {
        echo '..OK<br />';
    } else {
        $errorTxt = "Sorry, there was an error uploading your file.";
    }
    echo $newfilename . ' - OK<br />';
}

One would assume that the $errorTxt here would state the file already exists but it does not because $target_file and $newfilename will not be the same. The new name should be generated before the if (file_exists($target_file)) { check.

So – if you change the relevant code in your original to this the logic test will work but the files will still fail to upload.

$temp = explode(".", $_FILES["new_young"]["name"][$i]);
$newfilename = round( microtime(true) ) . '.' . end($temp);
$target_file = $target_dir . $newfilename;

if (file_exists($target_file)) {
    $errorTxt =  "Sorry, file already exists.";
    $uploadOk = 0;
}



if ($uploadOk == 0) {
    // if everything is ok, try to upload file
    echo $errorTxt;
} else {
    
    if (move_uploaded_file($_FILES["new_young"]["tmp_name"][$i], $target_file )) {
        //echo "The file ". basename( $_FILES["new_young"]["name"]). " has been uploaded.";
    } else {
        $errorTxt = "Sorry, there was an error uploading your file.";
    }
}

The issue now is that $newfilename = round( microtime(true) ) will generate the same integer – a large integer but the same. The precision derived from the microtime is lost so you could modify that to:

$newfilename =  str_replace( '.', '', strval( microtime( true ) ) ) . '.' . end( $temp ); 

With that done all should be well with your code – three images uploaded OK.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement