PHP Redirect with POST data
I did some research on this topic, and there are some experts who have said that it is not possible, so I would like to ask for an alternative solution.
My situation:
Page A: [checkout.php] Customer fills in their billing details.
Page B: [process.php] Generate an invoice number and store customer details in database.
Page C: [thirdparty.com] Third Payment Gateway (ONLY ACCEPT POST DATA).
Customer fills in their details and sets up their cart in Page A, then POSTs to Page B. Inside process.php, store the POSTed data inside the database and generate an invoice number. After that, POST the customer data and invoice number to thirdparty.com payment gateway. The problem is doing POST in page B. cURL is able to POST the data to Page C, but the problem is the page didn't redirect to page C. The customer needs to fill in Credit Card details on Page C.
The third party payment gateway did give us the API sample, the sample is POST the invoice number together with customer detail. We don't want the system to generate an excess of unwanted invoice numbers.
Is there any solution for this? Our current solution is for the customer to fill detail in Page A, then in Page B we create another page showing all the customer details there, wh开发者_高级运维ere the user can click a CONFIRM button to POST to Page C.
Our goal is for customers to only have to click once.
Hope my question is clear :)
Generate a form on Page B with all the required data and action set to Page C and submit it with JavaScript on page load. Your data will be sent to Page C without much hassle to the user.
This is the only way to do it. A redirect is a 303 HTTP header that you can read up on http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, but I'll quote some of it:
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.
The only way to achieve what you're doing is with a intermediate page that sends the user to Page C. Here's a small/simple snippet on how you can achieve that:
<form id="myForm" action="Page_C.php" method="post">
<?php
foreach ($_POST as $a => $b) {
echo '<input type="hidden" name="'.htmlentities($a).'" value="'.htmlentities($b).'">';
}
?>
</form>
<script type="text/javascript">
document.getElementById('myForm').submit();
</script>
You should also have a simple "confirm" form inside a noscript tag to make sure users without Javascript will be able to use your service.
/**
* Redirect with POST data.
*
* @param string $url URL.
* @param array $post_data POST data. Example: ['foo' => 'var', 'id' => 123]
* @param array $headers Optional. Extra headers to send.
*/
public function redirect_post($url, array $data, array $headers = null) {
$params = [
'http' => [
'method' => 'POST',
'content' => http_build_query($data)
]
];
if (!is_null($headers)) {
$params['http']['header'] = '';
foreach ($headers as $k => $v) {
$params['http']['header'] .= "$k: $v\n";
}
}
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if ($fp) {
echo @stream_get_contents($fp);
die();
} else {
// Error
throw new Exception("Error loading '$url', $php_errormsg");
}
}
$_SESSION is your friend if you don't want to mess with Javascript
Let's say you're trying to pass an email:
On page A:
// Start the session
session_start();
// Set session variables
$_SESSION["email"] = "awesome@email.com";
header('Location: page_b.php');
And on Page B:
// Start the session
session_start();
// Show me the session!
echo "<pre>";
print_r($_SESSION);
echo "</pre>";
To destroy the session
unset($_SESSION['email']);
session_destroy();
I have another solution that makes this possible. It requires the client be running Javascript (which I think is a fair requirement these days).
Simply use an AJAX request on Page A to go and generate your invoice number and customer details in the background (your previous Page B), then once the request gets returned successfully with the correct information - simply complete the form submission over to your payment gateway (Page C).
This will achieve your result of the user only clicking one button and proceeding to the payment gateway. Below is some pseudocode
HTML:
<form id="paymentForm" method="post" action="https://example.com">
<input type="hidden" id="customInvoiceId" .... />
<input type="hidden" .... />
<input type="submit" id="submitButton" />
</form>
JS (using jQuery for convenience but trivial to make pure Javascript):
$('#submitButton').click(function(e) {
e.preventDefault(); //This will prevent form from submitting
//Do some stuff like build a list of things being purchased and customer details
$.getJSON('setupOrder.php', {listOfProducts: products, customerDetails: details }, function(data) {
if (!data.error) {
$('#paymentForm #customInvoiceID').val(data.id);
$('#paymentForm').submit(); //Send client to the payment processor
}
});
I know this is an old question, but I have yet another alternative solution with jQuery:
var actionForm = $('<form>', {'action': 'nextpage.php', 'method': 'post'}).append($('<input>', {'name': 'action', 'value': 'delete', 'type': 'hidden'}), $('<input>', {'name': 'id', 'value': 'some_id', 'type': 'hidden'}));
actionForm.submit();
The above code uses jQuery to create a form tag, appending hidden fields as post fields, and submit it at last. The page will forward to the form target page with the POST data attached.
p.s. JavaScript & jQuery are required for this case. As suggested by the comments of the other answers, you can make use of <noscript>
tag to create a standard HTML form in case JS is disabled.
I'm aware the question is php
oriented, but the best way to redirect a POST
request is probably using .htaccess
, ie:
RewriteEngine on
RewriteCond %{REQUEST_URI} string_to_match_in_url
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^(.*)$ https://domain.tld/$1 [L,R=307]
Explanation:
By default, if you want to redirect request with POST data, browser redirects it via GET with 302 redirect
. This also drops all the POST data associated with the request. Browser does this as a precaution to prevent any unintentional re-submitting of POST transaction.
But what if you want to redirect anyway POST request with it’s data? In HTTP 1.1, there is a status code for this. Status code 307
indicates that the request should be repeated with the same HTTP method and data. So your POST request will be repeated along with it’s data if you use this status code.
SRC
You can let PHP do a POST, but then your php will get the return, with all sorts of complications. I think the simplest would be to actually let the user do the POST.
So, kind-of what you suggested, you'll get indeed this part:
Customer fill detail in Page A, then in Page B we create another page show all the customer detail there, click a CONFIRM button then POST to Page C.
But you can actually do a javascript submit on page B, so there is no need for a click. Make it a "redirecting" page with a loading animation, and you're set.
There is a simple hack, use $_SESSION
and create an array
of the posted values, and once you go to the File_C.php
you can use it then do you process after that destroy it.
I faced similar issues with POST Request where GET Request was working fine on my backend which i am passing my variables etc. The problem lies in there that the backend does a lot of redirects, which didnt work with fopen or the php header methods.
So the only way i got it working was to put a hidden form and push over the values with a POST submit when the page is loaded.
echo
'<body onload="document.redirectform.submit()">
<form method="POST" action="http://someurl/todo.php" name="redirectform" style="display:none">
<input name="var1" value=' . $var1. '>
<input name="var2" value=' . $var2. '>
<input name="var3" value=' . $var3. '>
</form>
</body>';
You can use sessions to save $_POST
data, then retrieve that data and set it to $_POST
on the subsequent request.
User submits request to /dirty-submission-url.php
Do:
if (session_status()!==PHP_SESSION_ACTIVE)session_start();
$_SESSION['POST'] = $_POST;
}
header("Location: /clean-url");
exit;
Then the browser redirects to and requests /clean-submission-url
from your server. You will have some internal routing to figure out what to do with this.
At the beginning of the request, you will do:
if (session_status()!==PHP_SESSION_ACTIVE)session_start();
if (isset($_SESSION['POST'])){
$_POST = $_SESSION['POST'];
unset($_SESSION['POST']);
}
Now, through the rest of your request, you can access $_POST
as you could upon the first request.
Try this:
Send data and request with http header in page B to redirect to Gateway
<?php
$host = "www.example.com";
$path = "/path/to/script.php";
$data = "data1=value1&data2=value2";
$data = urlencode($data);
header("POST $path HTTP/1.1\\r\
" );
header("Host: $host\\r\
" );
header("Content-type: application/x-www-form-urlencoded\\r\
" );
header("Content-length: " . strlen($data) . "\\r\
" );
header("Connection: close\\r\
\\r\
" );
header($data);
?>
Additional Headers :
Accept: \*/\*
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/74.0.3729.169 Safari/537.36
function post(path, params, method) {
method = method || "post"; // Set method to post by default if not specified.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
Example:
post('url', {name: 'Johnny Bravo'});
Here there is another approach that works for me:
if you need to redirect to another web page (user.php
) and includes a PHP variable ($user[0]
):
header('Location:./user.php?u_id='.$user[0]);
or
header("Location:./user.php?u_id=$user[0]");
精彩评论