[in new window] [back] [close]
[introduction] [FAQ] [search] [what's new] [index]

Example script to receive published files

<?php

/* this is an example of how a published file can be received from
 Ensembling automatically. This assumes we do all the provided
 security checks, but a form that already exists to do a file upload
 can work without these.  */

$file_field = 'file'; /* the name of the field in the $_FILES array
                       containing the file; the Ensembling user can
                       also set this, and obviously both sides have to
                       agree on what it is called, but this is the default. */

$file_destination = '/home/me/importedfiles'; /* where on this server to put the file received
                                               - don't forget the web server will need write 
                                               access to this directory */

$security_field = 'security'; /* the name of the field in $_POST where
                               Ensembling provides security check
                               information; the Ensembling user can
                               change this name, but both ends have to
                               agree on it; this is the default. */

$security_secret = '123456'; /* change this to a private value and enter
                             it as Ensembling's security secret; this is
                             our shared secret */

$expected_source_url = 'www.ensembling.com'; /* where the upload is coming form */

/* -------------------------------------------------- */

/* did the post come from Ensembling: check the IP address. Remove
 this section if the upload mechanism is for use from other clients as
 well */
if (empty($_SERVER['REMOTE_ADDR']) || 
    $_SERVER['REMOTE_ADDR'] != gethostbyname($expected_source_url)) 
{
  do_403('dont know you');
}

/* -------------------------------------------------- */

/* if this is not a post, send a 202 to acknowledge the request
 (Ensembling tries a test for this). Not essential: a simple exit
 will do if there is no $_POST */
if (empty($_POST)) { do_202('ping OK'); }

/* -------------------------------------------------- */

/* check the security. This is specific to Ensembling, so remove this
 section for general utiltiy, or if you are not bothered about this
 cross check. It sends a string in the nominated POST variable which
 is in two parts separated by a space. The first part is a 9 digit
 random number (different every time) and the second is an sha1
 encryption of the shared secret number concatenated with the random
 number. So by recreating and comparing the encrypted part this end
 from the shared secret and the given number we can check that the
 sender knows our shared secret */
if (empty($_POST[$security_field])) { do_403('missing security'); } 
if (strpos($_POST[$security_field], ' ') === FALSE) { do_403('security bad format'); }
list($plaintext, $encryptedtext) = explode(' ', $_POST[$security_field]);
if (sha1($security_secret . $plaintext) != $encryptedtext) { do_403('security check failed'); }

/* -------------------------------------------------- */

/* OK, we're now in a position to receive the file. (Consider what to
 do with any other post params that you may want processed, not
 illustrated here, bearing in mind we don't know the file suceeded
 transfering yet; for example, you might have a field which tells this
 script to email someone to say the file has arrived, or a field to vary
 which directory the file is uploaded to). */

if (empty($_FILES[$file_field])) { do_400('no file'); }

switch ($_FILES[$file_field]['error']) {
  case 0:
  case UPLOAD_ERR_NO_FILE:
    break;
  case UPLOAD_ERR_INI_SIZE:
  case UPLOAD_ERR_FORM_SIZE:
    do_413('too big');
  case UPLOAD_ERR_PARTIAL:
    do_500('partial transfer');
  default:
    do_400('unknown error');
}

$file_name = $_FILES[$file_field]['name'];

/* at the very least ban php etc, invoked by the web server. Be very
   careful if other file suffixes are handled unusually by the web
   server, e.g. if HTML files are executed by the PHP server, as any
   PHP code in there could then do anything. Much better to put the
   files outside the web server and fetch them yourself with PHP */

if (substr($file_name, -3) == '.php' ||
    substr($file_name, -2) == '.pl' ||
    substr($file_name, -2) == '.py') 
{ 
  do_403('file type not allowed'); 
}

/* replace any non-permitted characters, so we can be sure we can save the file */

$path_name = $file_destination . '/' . rawurlencode($file_name);

if (! move_uploaded_file($_FILES[$file_field]['tmp_name'], $path_name)) {
  do_500('cannot save file');
}

/* -------------------------------------------------- */

/* otherwise, give some clue that it was all ok */
echo <<<EOD
<html>
<head><title>upload OK</title></head>
<body><p>file uploaded correctly</p></body>
</html>
EOD;

/* -------------------------------------------------- */
function do_http_error($code, $s) { header("HTTP/1.0 {$code}"); echo $s; exit(); }
function do_202($s) { do_http_error('202 Accepted', $s); }
function do_400($s) { do_http_error('400 Bad Request', $s); }
function do_403($s) { do_http_error('403 Forbidden', $s); }
function do_404($s) { do_http_error('404 Not Found', $s); }
function do_413($s) { do_http_error('413 Request Entity Too Large', $s); }
function do_500($s) { do_http_error('500 Internal Server Error', $s); }

?>