1

I want to have a HTML form to send a file to my server by user. I need to know the exact time he started sending this file - not the time that the file was received (I can check received time e.g. by checking file modification time at server). This code should do this - when clicking "Submit" the current server time should be written to logsForSendingForm.txt and when the file receives time should be written to logsForReceivedForm.txt. Unfortunately, when sending the file, only the time when the file is received is written to logsForReceivedForm.txt - nothing is written to logsForReceivedForm.txt. What is interesting, if I don't select any file and click Submit, current time is written to both files.

If you don't know how to debug this, but you can suggest any other solution (maybe without AJAX), it's also OK, I don't need to do it like in this code.

<?php

if (isset($_POST['tickStart']))
{
    file_put_contents('logsForSendingForm.txt', time() . "\n", FILE_APPEND);
}
elseif (!empty($_FILES))
{
    file_put_contents('logsForReceivedForm.txt', time() . "\n", FILE_APPEND);
    $f = $_FILES['file'];
    $patch = str_replace('index.php', '', $_SERVER['SCRIPT_FILENAME']);
    copy($f['tmp_name'], $patch.$f['name']);
}

?><!DOCTYPE html>
<html>
    <head>
        <script src='http://code.jquery.com/jquery-2.1.0.min.js'></script>
        <script type='text/javascript'>
                function sending()
                {
                    $.ajax({
                        url: 'index.php',
                        type: 'POST',
                        data: { tickStart: true }
                    });

                    return true;
                }
        </script>
    </head>
    <body>
        <form action='index.php' method='post' enctype='multipart/form-data'>
            <input type='file' name='file'><br>
            <input type='submit' name='submit' value='Submit' onsubmit="return sending()">
        </form>
    </body>
</html>
  • 1
    Can't you just slide a var startime = new Date(); somewhere before the Ajax call, and pass it to the server? – TimSPQR Apr 28 '14 at 10:50
  • @TimSPQR, this will pass time from user's computer, not server's time, right? I need this to be server time, so nobody can "cheat". – user1809811 Apr 28 '14 at 11:23
  • you are going to have a big problem with concurrency because multiple "simultaneous" calls with file_put_contents to the same file will probably corrupt it. – denjello Apr 28 '14 at 12:25
  • If you can't use js for the user submit, then the first line in your php code needs to be a 'now' time variable, and then save it to the table when all the other user db stuff gets saved. – TimSPQR Apr 28 '14 at 14:16

1 Answers1

1

There needs to be a bit more checking done on your part, but here is some briefly tested code. I used microtime() instead of time because for small files there is no difference in seconds on my localhost. I also threw in something from here to help inform the user that their file was too big, for example. You might want to catch according to mime-type and inform them of that too...

I threw out Jquery because it seemed superfluous.

You might still get a corrupted file if (and when) multiple clients attempt to write to your logs. (That is why I added the | LOCK_EX flag to your append. I have not done any load-testing, so no guarantees there.) Database???

Otherwise, you'll probably also want to do some filename normalization to get rid of illegal / non-ascii characters. But that's another question that has been treated elsewhere.

Cheers.

EDIT: duration: 0.084668874740601 (for a 23mb file on localhost) duration: 0.0021710395812988 (for a 74k file on localhost)

<?php
    if (isset($_POST['tickStart']))
    {   
        // this is the moment the script began 
        $mtime1=$_SERVER['REQUEST_TIME_FLOAT'];
        $log = 'sent: ' . $mtime1;
    }
    if(isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) == 'post' && $_FILES['file']['size'] == 0){ 
        $postMax = ini_get('post_max_size'); 
        $fileMax = ini_get('upload_max_filesize');  
        $message = "Max filesize: $fileMax<br>Max postsize: $postMax";
        $log = 'file too large';
    }
        elseif (!empty($_FILES) && !empty($_POST) && $_FILES['file']['size'] > 0)
    {
        $f = $_FILES['file'];
        $patch = str_replace('index.php', '', $_SERVER['SCRIPT_FILENAME']);
        copy($f['tmp_name'], $patch.$f['name']);
        // this is the time NOW
        $mtime2=microtime(true);
        file_put_contents('logsForSendingForm.txt', $mtime1 . "\n", FILE_APPEND  | LOCK_EX);
        file_put_contents('logsForReceivedForm.txt', $mtime2 . "\n", FILE_APPEND  | LOCK_EX);
        $duration = $mtime2 - $mtime1;
        $log = $log . '\nduration: '.$duration;
        $message = $f['name'].' uploaded.';
    }
        else 
    {
        $log = 'no file selected';
        $message = 'Please choose a file.';
    }

?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <script type='text/javascript'>
            console.log('<?php print $log ?>');
        </script>
    </head>
    <body>
        <form action='index.php'  enctype='multipart/form-data' method='POST'>
            <input type='file' name='file'><br>
            <input type='hidden' value='true' name='tickStart'>
            <input type='submit' name='submit' value='Submit'>
        </form>
        <h2>
        <?php print $message; ?>

        </h2>
    </body>
</html>
Community
  • 1
  • 1
denjello
  • 531
  • 3
  • 13
  • doesn't work... the file was uploading for about 30 seconds, but difference between sent and rcvd time is 0.001, it just checked both times after uploading this file. I think that it doesn't work because this hidden input is sent on the same time that the file sending is done. – user1809811 Apr 28 '14 at 17:37
  • by the way, you really should be using something for your upload system like the answer here: http://stackoverflow.com/questions/166221/how-can-i-upload-files-asynchronously-with-jquery?rq=1 – denjello Apr 28 '14 at 19:10
  • If the changes work for you, you should mark this question as answered. – denjello May 03 '14 at 15:36
  • I tested this and it works fine on localhost. But when uploading to remote FTP server (and I tested it on two different), the duration always is very small, like 0.001, even if I was uploading the file for half a minute or something. And the sent time is the time that file was already fully sent. Any ideas what went wrong? – user1809811 May 03 '14 at 22:12