2

I am trying to write a script for uploading large files (>500MB). I would like to do some authentication before the upload is processed, eg:

$id = $_GET['key'];
$size = $_GET['size'];
$time = $_GET['time'];
$signature = $_GET['signature'];

$secret = 'asdfgh123456';

if(sha1($id.$size.$time.$secret) != $signature){
echo 'invalid signature';
exit;
}
process upload...

unfortunately php only runs this code after the file has been uploaded to a temp directory, taking up valuable server resources. Is there a way to do this before the upload happens? I have tried similar things with perl/cgi but the same thing happens.

Jack000
  • 157
  • 1
  • 10

6 Answers6

6

Wow, already 5 answers telling how it can't be done. mod_perl to the rescue, here you can reject a request before the whole request body is uploaded.

daxim
  • 39,270
  • 4
  • 65
  • 132
  • wow, thanks. you've given me a ray of hope :] I'm not a perl programmer (hence the php code), but I'll do some reading and see if I can make it work. – Jack000 Dec 29 '10 at 22:44
  • my authentication function now uses the PerlPostReadRequestHandler handler. I can probably put it further down the handler stack, but it's working fine as it is. – Jack000 Dec 30 '10 at 04:07
  • 1
    the flash uploader on the client side gets a bit confused and uploads for a bit before returning the error, but it's definitely stopping the upload on the server side. thanks! – Jack000 Dec 30 '10 at 04:11
  • Thanks. I'm uploading large files from Flash to ASP.NET. I've implemented an HttpModule that calls HttpContext.GetService(typeof(HttpWorkerRequest)) to retrieve an HttpWorkerRequest, which allows me access the entity body stream as it's being uploaded. This also allows me to prematurely close the connection for the worker request to immediately stop the upload on the client, for example, if I want to cancel the upload after performing some authentication. There is no confusion at all on the Flash client when I close the connection this way; the upload stops immediately. – Triynko Oct 03 '12 at 19:28
3

Apache is taking care of the upload before the PHP script is even invoked so you won't be able to get at it.

You can either split up the process into two pages (authentication, file upload page) or, if you need to do it all in one page, use an AJAX-esque solution to upload the file after authentication parameters are checked.

webbiedave
  • 48,414
  • 8
  • 88
  • 101
  • 1
    Except, you apparently can't access file size from JavaScript. http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=file+upload+size+javascript#q=file+upload+size+javascript+stackoverflow&hl=en&prmd=ivns&tbs=dsc:1&tbo=u&sa=X&ei=mKsbTcG-K4S8lQeH8PGrDA&ved=0CCwQmAcwAg&fp=6db204469b4cb2b1, though theoretically possible with limited support using HTML5-ish File API http://stackoverflow.com/questions/1606842/how-can-i-get-a-files-upload-size-using-simple-javascript/2474914#2474914 – Yahel Dec 29 '10 at 21:45
  • @yc: right. The file size cannot be checked client-side. It's a trade off. – webbiedave Dec 29 '10 at 21:49
  • my main concern is a malicious user DOSing the server with large invalid uploads. Is there any way to prevent this? – Jack000 Dec 29 '10 at 21:55
  • 1
    @Jack000, PHP is not the proper domain for combating DDOS attacks. Folks can post files to any uri, not just PHP ones. You need to look into lower-level network solutions. See: http://en.wikipedia.org/wiki/Ddos#Prevention_and_response – webbiedave Dec 29 '10 at 21:58
  • thanks for the tips. It looks like I'll have to figure something out at the apache level. – Jack000 Dec 29 '10 at 22:28
0

As far as I know, you cannot do that in PHP. PHP script is launched in response to a request, but a request is not "sent" until the file is uploaded, since the file being uploaded is a part of the request.

German Rumm
  • 5,782
  • 1
  • 25
  • 30
0

This is definitely not possible inside the PHP script you're uploading to.

The most simple possibility is indeed to provide authentication one step before the upload takes place.

If that is not an option, one slightly outlandish possibility comes to mind - using a RewriteMap and mapping it to an external program (it should be possible to make that program a PHP script).

Using RewriteMap it is possible to rewrite an URL based on the output of a command line program. If you use this directive to call a (separate) PHP script - you won't be able to use the user's session, though! - you would have access to the GET parameters before the request is processed.

If the processing fails (= the credentials are invalid), you could redirect the request to a static resource which would at least prevent PHP from starting up. (I assume the uploaded will be hogging some resources anyway, but probably less than if it were redirected to PHP.)

No guarantees whether this'll work! I have no own experience with RewriteMap.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
0

This is due to the fact that each HTTP request is a single contains all the of form/POST data, including the file upload data.

As such, I don't believe it's possible to handle a file upload request in this fashion irrespective of which scripting language you use.

John Parker
  • 54,048
  • 11
  • 129
  • 129
  • The server can certainly process the headers before the entire request is submitted. Whether the framework has access to that data is another matter entirely. – EricLaw Dec 29 '10 at 22:06
  • @EricLaw -MSFT- In theory it obviously can (it's just an in-progress I/O stream after all), but I've never see this ability exposed. – John Parker Dec 30 '10 at 10:48
0

I don't think you can do this. The best you can do is probably to run an AJAX function onSubmit to do your validation first, then if it returns valid then execute the POST to upload the file. You could set a $_SESSION in your AJAX script if the authentication is valid, then check for that session var in the upload script to allow the upload.

Calvin
  • 8,697
  • 7
  • 43
  • 51