Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading files without causing server side errors during the process

Tags:

php

upload

I continually make tweaks to my software and upload it to the server. As I have customers using my online software all the time, if a PHP file is partially uploaded (let's say it takes 3 seconds to upload) when a customer clicks a link (say at the 1 second mark) they get an error because the file is still uploading...

Parse error: syntax error, unexpected $end in /inc/functions.php on line 475

As I'm in Australia, our internet... well... "isn't very fast" is a nice way of putting it.

Are there any techniques used when uploading files so it does not cause errors for customers using the software?

Only thing I can thing of is uploading files to say another directory then running a PHP script that copies the files across super fast... But is there better solutions?

FINAL CODE

Thanks to Greg below I was able to figure out the best way to do things. Thought I'd share my final code. It's a bit rough but does the trick... Hopefully it helps someone

<?php

// root path
define('ABSPATH', dirname(__FILE__) . '/');

// messages
$GLOBALS['copied'] = array();
$GLOBALS['failed'] = array();
$GLOBALS['folders'] = array();

// you have to submit the form (added security)
if (isset($_POST['copy'])) {

    $GLOBALS['devuploads_folder'] = '_devuploads';

    function find_files($dir) {
        if ($dh = opendir(ABSPATH . $dir)) {
            while (($file = readdir($dh)) !== false) {

                // ignore files
                if ($file === '.' || $file === '..')
                    continue;

                // delete temporary files (optional)
                if ($file == '.DS_Store') {
                    unlink(ABSPATH . $dir . $file);
                    continue;
                }

                // determine paths                  
                $live_path = str_replace($GLOBALS['devuploads_folder'] . '/', '', $dir . $file);                
                $dev_file = $dir . $file;                   
                $live_file = $live_path;
                $dev_file_path = ABSPATH . $dir . $file;                    
                $live_file_path = ABSPATH . $live_path;

                // it's a file
                if (is_file(ABSPATH . $dir . $file)) {  

                    // check if the file has been updated or it's a brand newy
                    $updated_file = $new_file = false;
                    if (file_exists($live_file_path)) {                                 
                        $dev_file_modified = filemtime($dev_file_path);     
                        $live_file_modified = filemtime($live_file_path);                                               
                        if ($dev_file_modified > $live_file_modified)
                            $updated_file = true;                       
                    } else {
                        $new_file = true;
                    }

                    // move the file
                    if ($updated_file || $new_file) {
                        if (copy($dev_file_path, $dev_file_path . '.bak')) {
                            if (rename($dev_file_path . '.bak', $live_file_path))
                                if ($new_file)
                                    $GLOBALS['copied'][] = '<strong>New File:</strong> ' . $dev_file . ' moved to ' . $live_file;   
                                else
                                    $GLOBALS['copied'][] = $dev_file . ' moved to ' . $live_file;   
                            else
                                $GLOBALS['failed'][] = '<strong>Rename failed:</strong> ' . $dev_file . ' to ' . $live_file;
                        } else {
                            $GLOBALS['failed'][] = '<strong>Copy failed:</strong> ' . $dev_file . ' to ' . $dev_file . '.bak';
                        }
                    }

                // it's a folder
                } else if (is_dir(ABSPATH . $dir . $file)) {

                    // create new folder if it doesn't exist
                    if (!is_dir($live_file_path)) {
                        $GLOBALS['folders'][] = '<strong>Created:</strong> ' . $live_file;  
                        mkdir($live_file_path, 0755);   
                    }

                    // keep digging
                    find_files($dir . $file . '/');

                }

            }
            closedir($dh);
        }
    }

    find_files($GLOBALS['devuploads_folder'] . '/');

}

?>
<!DOCTYPE HTML>
<html>
<head>
    <title>Copy Changes</title>
    <style type="text/css">
    h1 {
        font: normal 20px Arial, Helvetica, sans-serif;
        line-height: 24px;
        }
    p, li {
        font: normal 14px Arial, Helvetica, sans-serif;
        line-height: 20px;
        }
    </style>
</head> 
<body>

<?php   
if (!empty($GLOBALS['failed'])) {
    echo '<h1>Errors</h1>';
    echo '<ul>';
    foreach($GLOBALS['failed'] AS $message) {
        echo '<li>' . $message . '</li>';
    }
    echo '</ul>';
}

if (!empty($GLOBALS['folders'])) {
    echo '<h1>New Folders</h1>';
    echo '<ul>';
    foreach($GLOBALS['folders'] AS $message) {
        echo '<li>' . $message . '</li>';
    }
    echo '</ul>';
}

if (!empty($GLOBALS['copied'])) {
    echo '<h1>Copied</h1>';
    echo '<ul>';
    foreach($GLOBALS['copied'] AS $message) {
        echo '<li>' . $message . '</li>';
    }
    echo '</ul>';
}

if (empty($GLOBALS['failed']) && empty($GLOBALS['folders']) && empty($GLOBALS['copied']))
    echo '<p>No updates made.</p>';
?>

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<input type="hidden" name="copy" value="1" />
<p><input type="submit" value="Copy Files" /></p>
</form>

</body>
</html>
like image 588
Ben Sinclair Avatar asked Jun 01 '12 01:06

Ben Sinclair


1 Answers

If your server is Linux (or other Unix variant), then the mv command is atomic and can do this sort of instantaneous update. First copy the file to a temporary name (like file.php.new), and then log in to the server and

mv file.php.new file.php

(this works even if file.php exists, it will be replaced by the new one).

like image 110
Greg Hewgill Avatar answered Sep 21 '22 18:09

Greg Hewgill