Jump to content

Can't access $_FILES after form submission


 Share

Recommended Posts

I have an index.php file which includes my form and code to move the user's uploaded file to s3. My HTML form calls a js function sendEmails() which makes an AJAX request to another php script dbSystem() to validate the emails input and add it to a database. Everything is working except that the php code in my index.php file (at the very bottom) does not execute. It's supposed to execute when the user uploads a file and presses submit but it doesn't go into the if statement. I tried putting the $fileName = basename($_FILES["fileName"]["name"]) statement before the if statement but I get an undefined index error. I put my a comment in my code to show which if statement I am talking about.

This is my HTML code in index.php:

<form action="javascript:void(0)" method="POST" id="files" enctype="multipart/form-data">
    <label class="col-md-4 col-form-label text-md-right">Select File:  <span class="text-danger">*</span></label>
    <input type="file" id="userFile" name="fileName" style="cursor: pointer; max-width: 170px;" onchange="enableBtn()">

    <label class="col-md-4 col-form-label text-md-right">Authorized Users:  <span class="text-danger">*</span></label>
    <input placeholder="Enter e-mail(s) here..." id="req" autocomplete="off"/>

    <button id="submitBtn" name="submitBtn" class="<?php echo SUBMIT_BUTTON_STYLE; ?>" onclick="return sendEmails()" disabled>Submit</button>
</form>

This is my php code in index.php:

<?php
$conn = new mysqli($servername, $username, $password, $db);
$sql = "SELECT sender_id, sender_email, receiver_emails, receiver_ids, file_name from filedrop_logs";
$result = mysqli_query($conn, $sql);

if ($result) {
    echo "<div class='outputDiv'>";
    echo "<table id='sharedOthers'>";
    echo "<thead><tr class='headings'>";
    echo "<th class='files'>Files</th>";
    echo "<th class='users'>Users</th>";
    echo "</tr></thead>";

    while ($row = mysqli_fetch_assoc($result)) {
        $receiverEmails = $row['receiver_emails'];
        $fileName = $row['file_name'];

        echo "<tbody id='bodyOthers'>";
        echo "<tr id='rowOthers'>";
        echo "<td>$fileName<br>";

        $objects = getListofObjects('FileDrop');
        foreach ($objects as $object) {
            $file = $object['Key'];
            $splits = explode('/', $file);
            if (end($splits) !== '') {
                $presignedUrl = getPresignedUrlForPrivateFile($object['Key'], '+20 minutes');
                $link = '<a href="'.$presignedUrl.'">Download</a>';
                echo $link;
            }
        }

        echo "&nbsp;&nbsp;&nbsp;&nbsp;<a href=''>Delete</a></td>";
        echo "<td>$receiverEmails</td>";
        echo "</tr></tbody>";
    }
    echo "</table></div>";
}
?>
<?php
//the if statement below doesn't execute

if(isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES["fileName"])) {
$fileName = basename($_FILES["fileName"]["name"]);
$error = $_FILES["fileName"]["error"];
$tmpName = $_FILES["fileName"]["tmp_name"];

if (isset(fileName) && $fileName != '' && $tmpName != '' && sys_get_temp_dir()) {
    $separator = DIRECTORY_SEPARATOR;
    $newDir = sys_get_temp_dir() . $separator . "FileDrop" . microtime(true);

    if (!file_exists($newDir)) {
        mkdir($newDir, 0777, true); // creates temp FileDrop directory
        $tempFilePath = $newDir . $separator . $fileName; // creates temp file inside FileDrop directory

        if (move_uploaded_file($tmpName, $tempFilePath)) { // moves file to tmp folder
            $s3FileName = "FileDrop" . substr($newDir, 4) . $separator . $fileName;
            $result = putFileToS3($s3FileName, $tempFilePath, 'public-read');
            deleteDir($newDir);
        }
    }
}
}
?>

This is my js code in case you want to see it:

function sendEmails() {
var fileData = $('#userFile').prop('files')[0];
var formData = new FormData();
formData.append('tags', JSON.stringify(tags));
formData.append('fileName', fileData);
$.ajax({
    type: "POST",
    url: "../FileDrop/dbSystem.php",
    processData: false,
    contentType: false,
    data: formData,
    success: function(result) {
        result = JSON.parse(result);
        if (result.validity === "valid emails") {
            location.reload();
            resetInputs(); //IMPORTANT
            $(".outputDiv").show();
        }
        else {
            var tagsBrackets = result.emails.toString().replace(/[\[\]']+/g,'');
            var tagsQuotes = tagsBrackets.replace(/['"]+/g, '');
            var tagsInvalid = tagsQuotes.replace(/,/g, ", ");
            $('#alertModal').modal({show:true});
            document.getElementById('invalid').textContent = tagsInvalid;
        }
    }
});
return false;
}

I've been stuck on this for so long, so I'd really appreciate the help!!

Link to comment
Share on other sites

The first 'isset' in the if is unnecessary. That will always be set to something. Did you 'echo' the other parameters to be sure they contain what you expect? Do you have errors turned on?

error_reporting(E_ALL);

 

Link to comment
Share on other sites

Posted (edited)

@gw1500se Yes I have done all that. I actually ended up moving that php codeblock in index.php to dbSystem.php (the part that's not working). I saw many solutions online that did it in that way so I tried it, but I'm still getting the same thing. Also, I removed the isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' parts from the if statement, since dbSystem.php is called through AJAX after form submission.

Edited by viktor122
Link to comment
Share on other sites

i tried your client-side code and it works for me. however, the things i bypassed or added to make it work, which you didn't include, may have altered the operation of the code. it is always helpful if you post complete, working, code.

you may want to log the $_FILES information on the server so that you can see what it actually is. add something like the following to the php code in the file that's the target of the ajax call -

file_put_contents('log.txt',print_r($_FILES,true),FILE_APPEND);

your post method form processing code should have always been in the target file of the ajax call. your form processing code should -

  1. detect if a post method form was submitted, i.e. you need the if($_SERVER['REQUEST_METHOD'] === 'POST'){...} logic.
  2. next, if you exceed the post_max_size setting, which is what i think is probably occurring, both the $_POST and $_FILES arrays will be empty. you must test for this condition after item #1 above, and setup a message for the user telling them that the total size of the form data was too large. you would also want to log this information, including the actual size of the post data, so that you, the developer/programmer, will know that it is occurring as the result of user actions on your site.  
  3. if the $_FILES array is not empty, you can then use elements in that array. you must next test if the ['error'] element is zero (no errors) or some other value (see the upload handling section in the php.net documentation for all the possible error values.) for errors that the user has control over, you need to setup a unique and helpful error message telling the user what was wrong with what they did. for the errors that the user has no control over, you should log the actual error information and setup a general failure message for the user.
  4. only after you have done the above three things, will you have actual uploaded file information that you can use.
Link to comment
Share on other sites

@mac_gyver Thanks for the explanation. I tried changing my code the way you said. I'm a little confused though because how do I check the post_max_size and error without using $_FILES? I get Undefined index 'fileName' whenever I try to access it. I also don't understand what file_put_contents('log.txt',print_r($_FILES,true),FILE_APPEND) is for. Is log.txt the file uploaded by the user because again wouldn't I have to access $_FILES to get that? I included my new code below.

HTML code in index.php is the same. I moved the php code in index.php to dbSystem.php so this is how index.php looks now:

<?php
$conn = new mysqli($servername, $username, $password, $db);
$sql = "SELECT sender_id, sender_email, receiver_emails, receiver_ids, file_name from filedrop_logs";
$result = mysqli_query($conn, $sql);

if ($result) {
    echo "<div class='outputDiv'>";
    echo "<table id='sharedOthers'>";
    echo "<thead><tr class='headings'>";
    echo "<th class='files'>Files</th>";
    echo "<th class='users'>Users</th>";
    echo "</tr></thead>";

    while ($row = mysqli_fetch_assoc($result)) {
        $receiverEmails = $row['receiver_emails'];
        $fileName = $row['file_name'];

        echo "<tbody id='bodyOthers'>";
        echo "<tr id='rowOthers'>";
        echo "<td>$fileName<br>";

        $objects = getListofObjects('FileDrop');
        foreach ($objects as $object) {
            $file = $object['Key'];
            $splits = explode('/', $file);
            if (end($splits) !== '') {
                $presignedUrl = getPresignedUrlForPrivateFile($object['Key'], '+20 minutes');
                $link = '<a href="'.$presignedUrl.'">Download</a>';
                echo $link;
            }
        }

        echo "&nbsp;&nbsp;&nbsp;&nbsp;<a href=''>Delete</a></td>";
        echo "<td>$receiverEmails</td>";
        echo "</tr></tbody>";
    }
    echo "</table></div>";
}
?>

dbSystem.php code:

<?php
$fileName = $_POST['fileName'];
file_put_contents($fileName,print_r($_FILES,true),FILE_APPEND);

if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES["fileName"])) {
    if ($_FILES["fileName"]["size"] > ini_get('post_max_size')) {
        echo "file too big";
    }
    else {
        if ($_FILES && $_FILES["fileName"]["error"] === 0) {

            $fileName = basename($_FILES["fileName"]["name"]);
            $error = $_FILES["fileName"]["error"];
            $tmpName = $_FILES["fileName"]["tmp_name"];
            echo $fileName;
            echo $error;
            echo $tmpName;
            echo "yes";

            if (isset($fileName) && $fileName != '' && $tmpName != '' && sys_get_temp_dir()) {
                $separator = DIRECTORY_SEPARATOR;
                $newDir = sys_get_temp_dir() . $separator . "FileDrop" . microtime(true);

                if (!file_exists($newDir)) {
                    mkdir($newDir, 0777, true); // creates temp FileDrop directory
                    $tempFilePath = $newDir . $separator . $fileName; // creates temp file inside FileDrop directory

                    if (move_uploaded_file($tmpName, $tempFilePath)) { // moves file to tmp folder
                        $s3FileName = "FileDrop" . substr($newDir, 4) . $separator . $fileName;
                        $result = putFileToS3($s3FileName, $tempFilePath, 'public-read');
                        deleteDir($newDir);
                    }
                }
            }
        }
    }
}
else {
    echo "no";
}
function deleteDir($dirPath)
{
    if (!is_dir($dirPath)) {
        if (file_exists($dirPath) !== false) {
            unlink($dirPath);
        }
        return;
    }
    if ($dirPath[strlen($dirPath) - 1] != '/') {
        $dirPath .= '/';
    }
    $files = glob($dirPath . '*', GLOB_MARK);
    foreach ($files as $file) {
        if (is_dir($file)) {
            deleteDir($file);
        } else {
            unlink($file);
        }
    }
    rmdir($dirPath);
}


?>

In the dbSystem.php code, the first if statement is not even executed because $_FILES is empty so not sure how to work around that.

Also, js code is the same.

Link to comment
Share on other sites

If you are submitting your form to the same page that form is on, it is typically good practice to put the form processing logic at the top of the page. That way if you need to show the results of the new data or show form processing errors you can generate that within the content of the page. I have not run your code, but I notice that the JavaScript that is called from within the action parameter of the form returns false at the end of the script.

 

If you return false within the action parameter of a firm, then the form is never submitted. That may be your problem.

Link to comment
Share on other sites

Posted (edited)

@Psycho I have moved that php code to dbSystem.php. The reason I have return False there is because I want the page to reload once the user submits the form. If their email input isn't valid however, I want to display an alert and continue allowing them to change their input until all emails are valid. Only when they are valid and user presses submit, the page will reload. Validity will be checked in dbSystem.php as well. I'm still having trouble getting values for $_FILES in dbSystem.php though.

Edited by viktor122
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.