Redirect POST request and keep data. Possible? - php

My problem is simple. I need to upload a file directly to the correct server (which has currently low workload).
Therefore I do:
<?php
$server = file_get_contents('http://my-api.com/upload-server.php'); // returns url
?>
then i print my form like
<form method="post" action="<?php echo $server; ?>"...
Now I would like to shift this step to when the upload starts, like so:
<form method="post" action="http://my-api.com/upload-gateway.php"...
this url should do a redirect to the "real" server.
So that the upload page doesn't slow down loading and I have static html code that I can cache, embed etc...
Problem is that this works perfetly fine with get requests but not with post requests.
The request seems like to get transformed into a get request when redirecting using the location header. All post data is lost.
Is this impossible or am I doing it wrong? And yes, I considered a remote dynamic javascript that prints the html code with the correct server in the first place. I would rather like not to do that...
any ideas? Maby alternative uplod techniques?
edit:
this is the exact html code i use:
<form method='post' enctype='multipart/form-data' action='http://storage.ivana.2x.to/rest.php?action=target'>
<input type=hidden name=testfield value="test">
File to upload: <input type=file name=upfile><br>
Notes about the file: <input type=text name=note><br>
<br>
<input type=submit value=Press> to upload the file!
</form>
this is the redirect code i use:
if($_GET["action"] == "target") {
header("Location: http://storage.ivana.2x.to/rest.php?action=test");
}
this is the output code i use to see the results:
if($_GET["action"] == "test") {
echo "<pre>";
var_dump($_POST);
var_dump($_GET);
var_dump($_FILES);
}
the result when uploading a small file looks like:
array(0) {
}
array(1) {
["action"]=>
string(4) "test"
}
array(0) {
}

If you really want to load balance through the code while potentially caching the page with the upload form, first select the default download server (url); then, onSubmit call the server and find the best upload target and adjust the action attribute accordingly.
With this method, users who do not activate JS still get what they want, users with JS enabled get the better upload target, and you can still cache. Additionally, the timing of the cache request could potentially be more opportunistic, since the URL request will occur very shortly before the actual upload.
The only hitch will be the call to get the URL, which you can more easily performance tune (I imagine) than the process you are describing above. Uploading a file twice through a header directive and/or cURL call don't seem like a good tradeoff for caching a single html file, IMO. But I don't know what you're up against, either.
If you don't want to heavily administer the server environment and introduce load balancing, this is the option I would suggest.
Note, also, I am not a server administrator by trade.

You could try returning a code 302 (temporary moved), not 100% that would let your browser post the data to the changed url though, but it's worth something to check out.
[Edit]
According to this wikipedia article, the POST data would be converted to GET, which probably won't work for a file upload.

This is not a good solution. The file will be uploaded in it's entirety before the PHP script is even started. This means that if you succeed with what you're trying to do the client will have to upload the file twice!
I recommend that you try to figure out which server to send the request to when you're creating the form, so the action attribute in the form tag will point directly to the lesser loaded machine.
Or even better: use a serverside loadbalancer and make your HTTP infrastructure transparent to the browser. This is essentially a sysadmin problem.

i might be wrong but.. your form's action points to ?action=target and in your rest.php you do a header to "?action=test" well of course you wont find your $POST nor your $FILES!... a header() does not send those variables..
if you want to send your post and your file to a differente location you'll need to use the cUrl library.. but it wont be easy :)
Good Luck

Related

PHP allow user to only view file after form submission

I have a basic file. The user can only view the file after a successfull form submission.
Now I know I have a variety of options I could use including placing it in a dir and modifying my .htaccess and then use a parameter which I pass through a routing script to let the user view the file as pointed out by numerous answers to somewhat similar questions. (which would probably be best option)
However Im just curious about something. "How Secure" would the following be.
Both files reside in a directory called xyz
Directory public_html/xyz
Form.php
<form method ="post" action="displayInfo.php" />
displayInfo.php
Now what I would like to know is IF i set the following code at the start of displayInfo.php would it stop with unauthorized access (i.e. prevent user from viewing the file IF he / she did not successfully submit the form)
if($_SERVER['REQUEST_METHOD'] !== 'POST'){
die("first submit the form")
}
No it wouldn't. I could defeat your security precaution with a simple cURL command:
curl -X POST https://example.com/displayInfo.php
The check for a POST request will pass, because it indeed a post request. However, it has absolutely none of the data you wanted.

PHP: Input to .txt AND html page

So, I got my PHP script to store input in a .txt file, however, something is not working with my html page. I want to output text to both a .txt file as well as a div on my html page.
I personally think it has to do with the fact that the script itself is on a separate page and I'm refreshing the page so there is never an opportunity to show up. I feel like what the PHP script should do is pull from the .txt file instead. But not sure.
I've tried action="" and putting the PHP on the same page but that didn't write to the .txt file. The ONLY way it has written to the .txt file is when I do action="[php file]".
Any ideas?
HTML:
The reference:
<?php require_once('storeText.php');?>
The Form:
<form id="post" name="post" action="storeText.php" method="post">
<textarea name="msg" rows="5"></textarea>
<input class="button" name="submit" type="submit" value="SQUAWK!"/>
</form>
Where I want the input to go on the page:
<div class="menuItem" >
<?php echo $msg; ?>
</div>
PHP:
storeText.php
<?php
if ( isset( $_POST['submit'] ) ) {
$filename = 'posts.txt';
$msg = (isset($_POST['msg']) ? $_POST['msg'] : null);
if ( is_writable( $filename ) ) {
if ( $handle = fopen( $filename, 'a') ) {
fwrite( $handle, $msg );
echo "Success, wrote ( $msg ) to file ( $filename )";
fclose( $handle );
} else {
echo "Could not open file.";
}
} else {
echo "File not writable.";
}
header("Location: profile.html");
}
?>
FYI- I decided to use an alternate script for all the fwrite() haters out there... same deal... won't write to html page.
ALTERNATE PHP:
<?php
if(isset($_POST['submit']))
{
$file = 'posts.txt';
// Open the file to get existing content
$msg = file_get_contents($file);
// Append new content to the file
$msg .= (isset($_POST['msg']) ? $_POST['msg'] : null);
// Write the contents back to the file
file_put_contents($file, $msg);
header("Location: profile.html");
}
?>
Nikhil Patel pretty much beat me to this in the comments on your question, but let me try to offer some more detail.
I'm not 100% sure I'm reading your question correctly, so correct me if I'm wrong on any of this: You have a form on profile.html, which sumbits to storeText.php. StoreText.php writes the file and redirects back to profile.html. Then you want profile.html to display the same $msg variable that got written to the text file, but it isn't doing that. Is that right?
You may have a problem with expecting a .html file to be executed as PHP code. I don't know how your Web server is set up, but normally only .php files are parsed by PHP. You might try renaming profile.html to profile.php and see if that makes a difference. From here on out, I'll be assuming that profile.html is being parsed as PHP; if I'm wrong about that, you'll probably have to rename the file.
The real problem is the redirect. You could take either of two different approaches here. One way to do it would be to include storeText.php in profile.html and have the form submit to profile.html. Then the $msg variable would be available in profile.html and should display. The other approach would be a POST/redirect/GET setup in which the form submitted to storeText.php, which did the work and redirected the user back to profile.html.
The thing is, you can't do both the include and the redirect. That's where you're running into problems. See, each HTTP request from the client, including the new request that the client sends in response to the redirect header, causes your script to be run again from scratch. The brand new profile.html that starts up after the redirect has never seen the $msg variable that contained the value that was written to the file. The reason submitting to profile.html didn't work is that it includes all the code from storeText.php, including the redirect, and even if you redirect to the same file, it's still a new request.
If you want to use the redirect, you'll need some way of storing that variable on the server side so that profile.html can get to it. The usual way of doing this is with sessions. Just have both profile.html and storeText.php set up sessions, have storeText.php save $msg to the session, and have profile.html pull it back out. Then remove the require_once('storeText.php'); line from profile.html, since you don't need that logic there anymore.
If you're not attached to the redirect, then you can do what I normally do (and what Nikhil Patel suggested in the comments). I normally put my form-displaying logic and my form-processing logic in one file, which decides what to do based on whether there's form input. I find this makes it easier to do validation, among other things, but I digress. All you really have to change here is to have the form submit to profile.html (action="" will work fine) and remove the redirect from storeText.php. Then everything will work as you expect.
However, both these approaches are completely wrong if the whole point of what you're doing is to make profile.html output whatever's in the text file, regardless of whether or not you're seeing it right after the form submission. In that case, don't worry about keeping that $msg variable at all. Keep storeText.php pretty much as it is, including the redirect. Remove the include from profile.html. Then, instead of having profile.html just try to echo $msg, have it open the file and echo its contents. (You can even set up a loop to read in one line at a time and put each one in a separate div if you want.)
On re-reading your question, I can't quite tell which behavior you actually want. Your first version of storeText.php only stores the new content in $msg, and uses the fopen/fwrite/etc. functions to append it to the file. So if $msg did survive the redirect (e.g. if you stored it in a session), the user would only see the new bit that was added to the file. The alternate version loads the file into $msg, appends the new content to that, and overwrites the file with $msg. If $msg survived the redirect in that case, the user would see the entire contents of the file.
However, in either case, the user would only see the results right after submitting the form; a fresh GET request to profile.html would still show an empty div. If you want the information to be displayed any time a user views profile.html, reading it from the file is the only option.
By the way, you may already know this but it is worth making explicit anyway: Do not display any values you got from the user without escaping them. If you do, then your page will allow an attacker to input malicious code and have it run in your users' browsers. This applies whether you got the values from the last form input or from a file. Read up on cross-site scripting (XSS) at IT Security StackExchange or OWASP.org.
Use File Put Content to store data on any file

Reserve file for ajax request only

I have a massive of scripts that my core application
include('JS/gramp.php');
include('JS/est.php');
include('JS/curest.php');
include('JS/memomarker.php');
include('JS/local----------.php');
include('JS/poirel.php');
include('JS/maplayers.php');
include('JS/trafficinc.php');
include('JS/plannedtraffic.php');
include('JS/transportissues.php');
include('JS/cams_traff.php');
include('JS/places2.php');
Now these are all being moved to a on the fly loading, to reduce the size of the application on load
if(button_case_curtime==true){
$(".jsstm").load("<?php echo $core_dir; ?>JS/curresttime.php?la=<?php echo $caseset['iplat']; ?>&lo=<?php echo $caseset['iplong']; ?>&h=<?php echo $days_h; ?>");
rendermap = true;
}
issue! the application requires these files to be secure, the data involved requires that no one can access.
The ONLY file that will ever request these files will be index.php
Any input or idears would be fantastic!
There is no way to provide a file to the browser without also providing it to a user.
You could configure your server to only supply the files given an extra HTTP header (which you could add with JS), but nothing would stop people from sending that header manually or just digging the source out of the browser's debugging tools.
Any user you give the files to will have access to the files. If you want to limit which users have access to them, then you have to use auth/authz (which you'll want to apply to the index.php file as well so that unauthorised users don't just get JS errors or silent failure states).
No. What you are trying to do is not possible. Ajax requests are not special. They are just HTTP requests. End points created for Ajax should be secured with authentication/authorization just like any other HTTP request end point.
This is a trivial solution that will solve your problem half-way. Request them via a POST request, like so:
$.post('JS/maplayers.php', {'ajax':true}, function(){});
Notice the POST variable 'ajax'. In the file maplayers.php, add to the beginning the following code:
if((!isset($_POST['ajax']))) {
die('Invalid request, only ajax requests are permitted');
}

Cancel an HTTP POST request server side

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.
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.
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.
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.
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.
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.
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.

How do I offer an Ajax POST response to the user as a download?

I'm trying to include a vCard export function in an existing page full of account information.
The ugly methods would involve 1, submitting a form to the same page, processing it and re-rendering the whole page, or 2, a GET targeting an iframe on the page. I'd really like to avoid both of those, but I may have to use #2 to achieve the goal.
Right now I have:
<input type="image" src="/intra/imgs/icons/vcard.png" onclick="$.post('/intra/vcard.php', { id: '992772', type: 'sponsor'});">
Which works in the sense that if I watch XHR activity in Firebug I see the request come back with the correct response, full of vCard formatted data. However it does not prompt the user to download the response as a file, even though the card is sent with:
header('Content-Type: text/x-vcard');
header("Content-Disposition: attachment; filename={$this->name_first}{$this->name_last}.vcf");
Am I doing something wrong, or is this just not possible?
I'm confused as to what exactly the problem is. Why not just do something like:
<input type="image"
src="/intra/imgs/icons/vcard.png"
onclick="window.location='/intra/vcard.php?id=992772&type=sponsor';">
And then return the appropriate download headers on vcard.php? When the browser gets those, it will stay on the same page and prompt for download. You will have to change your code to handle the variables as $_GET instead of $_POST but you should be using GET for this anyways.
EDIT as pointed out in the comments, it would be even more appropriate to do this:
<img src="/intra/imgs/icons/vcard.png">
As then it would be accessible to users with javascript disabled.
Yeah, you can't trigger a download from xhr. Only way I've found is option #2, use an iframe.
Perhaps a jquery plugin (I'm assuming you're using jquery) is an overkill for just this purpose, but this may be of use to you.
check if the filename ´{$this->name_first}{$this->name_last}.vcf´) is valid and the http-response in firebug! (tab network, click on the response).
is the content there and correct?
is the content-length correct?
what about the http-status?
Generate you content during post, then redirect to that content.

Categories