Chuyển hướng PHP với dữ liệu POST


241

Tôi đã thực hiện một số nghiên cứu về chủ đề này, và có một số chuyên gia đã nói rằng điều đó là không thể , vì vậy tôi muốn hỏi một giải pháp thay thế.

Hoàn cảnh của tôi:

Trang A: [checkout.php] Khách hàng điền vào chi tiết thanh toán của họ.

Trang B: [process.php] Tạo số hóa đơn và lưu trữ chi tiết khách hàng trong cơ sở dữ liệu.

Trang C: [thirdparty.com] Cổng thanh toán thứ ba (CHỈ CHẤP NHẬN DỮ LIỆU BÀI ĐĂNG).

Khách hàng điền vào các chi tiết của họ và thiết lập giỏ hàng của họ trong Trang A, sau đó POST đến Trang B. Bên trong process.php, lưu trữ dữ liệu POST trong cơ sở dữ liệu và tạo số hóa đơn. Sau đó, POST dữ liệu khách hàng và số hóa đơn lên cổng thanh toán của thirdparty.com. Vấn đề là thực hiện POST ở trang B. cURL có thể POST dữ liệu lên Trang C, nhưng vấn đề là trang không chuyển hướng đến trang C. Khách hàng cần điền chi tiết Thẻ tín dụng trên Trang C.

Cổng thanh toán bên thứ ba đã cung cấp cho chúng tôi mẫu API, mẫu được POST số hóa đơn cùng với chi tiết khách hàng. Chúng tôi không muốn hệ thống tạo ra vượt quá số lượng hóa đơn không mong muốn.

Có giải pháp nào cho điều này? Giải pháp hiện tại của chúng tôi là cho khách hàng điền chi tiết vào Trang A, sau đó trong Trang B, chúng tôi tạo một trang khác hiển thị tất cả các chi tiết của khách hàng ở đó, nơi người dùng có thể nhấp vào nút CONFIRM để POST lên Trang C.

Mục tiêu của chúng tôi là khách hàng chỉ phải nhấp một lần.

Hy vọng câu hỏi của tôi là rõ ràng :)


Tôi không nghĩ là trùng lặp cho điều này, đó là vì mục tiêu của tôi là trong một trang PHP, truyền dữ liệu POST và chuyển hướng nó. Tôi không nghĩ là có thể làm được. Chỉ cần tìm kiếm chuyên gia bất kỳ thay thế cho nó
Shiro

308 mã chuyển hướng?
dùng2284570

Câu trả lời:


212

Tạo một biểu mẫu trên Trang B với tất cả dữ liệu và hành động cần thiết được đặt thành Trang C và gửi nó với JavaScript khi tải trang. Dữ liệu của bạn sẽ được gửi đến Trang C mà không gặp nhiều rắc rối cho người dùng.

Đây là cách duy nhất để làm điều đó. Chuyển hướng là một tiêu đề HTTP HTTP 30 mà bạn có thể đọc trên http://www.w3.org/Prot Protocol / rfc2616 / rfc2616-sec10.html , nhưng tôi sẽ trích dẫn một số tiêu đề:

Có thể tìm thấy phản hồi cho yêu cầu theo một URI khác và NÊN được truy xuất bằng phương thức GET trên tài nguyên đó. Phương thức này tồn tại chủ yếu để cho phép đầu ra của tập lệnh được kích hoạt POST để chuyển hướng tác nhân người dùng đến tài nguyên đã chọn. URI mới không phải là tài liệu tham khảo thay thế cho tài nguyên được yêu cầu ban đầu. Phản hồi 303 PHẢI KHÔNG được lưu trong bộ nhớ cache, nhưng phản hồi cho yêu cầu thứ hai (được chuyển hướng) có thể được lưu trong bộ nhớ cache.

Cách duy nhất để đạt được những gì bạn đang làm là với một trang trung gian gửi người dùng đến Trang C. Đây là một đoạn nhỏ / đơn giản về cách bạn có thể đạt được điều đó:

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

Bạn cũng nên có một biểu mẫu "xác nhận" đơn giản bên trong thẻ noscript để đảm bảo người dùng không có Javascript sẽ có thể sử dụng dịch vụ của bạn.


2
Mục tiêu của tôi là trong Trang A -> Trang C, Trang B là bộ điều khiển (logic nghiệp vụ) tạo số hóa đơn. Từ chế độ xem hệ thống là Trang A-> Trang B-> Trang C, nhưng từ chế độ xem người dùng phải là Trang A-> Trang B, họ sẽ không bao giờ phát hành Trang B tồn tại.
Shiro

3
@Peeter: gợi ý thông minh +1. Vấn đề duy nhất là khi người dùng trên nút đẩy lại của Trang C được gửi lại cho Trang C. Ngoài ra, bạn đã quên mã hóa $a$bbằng cách sử dụng htmlentities/htmlspecialchars, hãy xem stackoverflow.com/questions/6180072/php-forward-data-post/
tựa

8
Câu hỏi ở đây là nếu Javascript bị vô hiệu hóa trên máy khách thì sao? Trang B sẽ không chuyển hướng đến trang C, phải không?
Imran Omar Bukhsh

24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>bên trong<form>
nullable

3
các languagethuộc tính bị phản đối, nó phải là<script type="text/javascript">...</script>
Alex W

34
/**
 * Redirect with POST data.
 *
 * @param string $url URL.
 * @param array $post_data POST data. Example: array('foo' => 'var', 'id' => 123)
 * @param array $headers Optional. Extra headers to send.
 */
public function redirect_post($url, array $data, array $headers = null) {
    $params = array(
        'http' => array(
            '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");
    }
}

17
Mặc dù lúc đầu, điều này cũng có vẻ tốt hơn câu trả lời được chấp nhận, tôi lưu ý rằng nó không chuyển hướng đến trang được cung cấp $url- Nó chỉ thay thế nội dung của trang hiện tại bằng nội dung của $urltrang. Điều quan trọng , mã php trong $urltrang không được đánh giá.
iPadDeveloper2011

@ iPadDeveloper2011, trong URL, bạn không có mã PHP! Mã PHP được thực thi trong SERVER, không phải trong máy khách.
Eduardo Cuomo

1
redirect_post(), đó là phía máy chủ, mã php, gửi yêu cầu đến SERVER cho a $url. Nếu đó $urllà một .phptrang, tôi lưu ý rằng php không được đánh giá - html được trả về với các thẻ php vẫn còn trong đó. Không phải là toàn bộ điểm để gửi dữ liệu POST đến một kịch bản phía máy chủ?
iPadDeveloper2011

2
@EduardoCuomo phương pháp này chỉ hoạt động với các url absoulte, vì cách fopen () hoạt động: php.net/manual/en/feft.fopen.php Đây vẫn là một câu trả lời khá tiện lợi.
Omn

@Omn bạn nói đúng! "Điều này không hoạt động với URL tương đối?" không phải là một câu hỏi, là một tuyên bố. Xin lỗi vì sự nhầm lẫn
Eduardo Cuomo

25

Tôi có một giải pháp khác làm cho điều này có thể. Nó đòi hỏi khách hàng phải chạy Javascript (mà tôi nghĩ là một yêu cầu công bằng ngày nay).

Chỉ cần sử dụng yêu cầu AJAX trên Trang A để tạo số hóa đơn và chi tiết khách hàng của bạn trong nền (Trang B trước đó của bạn), sau đó khi yêu cầu được trả lại thành công với thông tin chính xác - chỉ cần hoàn thành việc gửi biểu mẫu qua cổng thanh toán của bạn (Trang C).

Điều này sẽ đạt được kết quả của bạn về người dùng chỉ cần nhấp vào một nút và tiến tới cổng thanh toán. Dưới đây là một số mã giả

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 (sử dụng jQuery để thuận tiện nhưng tầm thường để tạo Javascript thuần túy):

$('#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
  }
});

1
Giải pháp này có một vấn đề, nếu ai đó tắt JavaScript trong trang này, hãy làm mới và gửi, nó sẽ đi đến trang thanh toán mà không lưu bất cứ điều gì. đây có thể là kẽ hở.
caoglish

2
Sau đó, chỉ đặt hành động PaymentForm với Javascript? Nếu JS bị vô hiệu hóa, biểu mẫu sẽ không được gửi.
MikeMurko

Người dùng tắt JS không gây ra sự cố cho chúng tôi - lý do chúng tôi phải truy cập Trang B có thể là để tạo dấu vân tay hoặc thêm mã đặt hàng, v.v. khi kết quả quay lại với chúng tôi từ bên thứ 3 mà không có mã đặt hàng, chúng tôi không nên chấp nhận đơn đặt hàng. Đây là một giải pháp tốt nếu JS được chấp nhận.
Coder

19

$ _SESSION là bạn của bạn nếu bạn không muốn gây rối với Javascript

Giả sử bạn đang cố gắng gửi email:

Trên trang A:

// Start the session
session_start();

// Set session variables
$_SESSION["email"] = "awesome@email.com";

header('Location: page_b.php');

Và trên trang B:

// Start the session
session_start();

// Show me the session!  
echo "<pre>";
print_r($_SESSION);
echo "</pre>";

Để phá hủy phiên

unset($_SESSION['email']);
session_destroy();

Tại sao bạn coi điều này là kém an toàn hơn phiên bản javascript?
Adam Baranyai

1
không, ý tôi là không so với javascript. Nói chung, chỉ có $ _SESSION có thể kém an toàn hơn một chút so với nói $ _SESSION + cookie, mặc dù $ _SESSION khá an toàn. Thêm thông tin ở đây: stackoverflow.com/questions/17413480/session-spoofing-php
Robert Sinclair

và làm thế nào để đóng phiên?
Muhammad đã nói

Bạn có cần phải đóng phiên?
Ivan P.

6

Bạn có thể để PHP thực hiện POST, nhưng sau đó php của bạn sẽ nhận được kết quả, với đủ loại biến chứng. Tôi nghĩ đơn giản nhất là thực sự cho phép người dùng thực hiện POST.

Vì vậy, loại những gì bạn đề xuất, bạn sẽ thực sự nhận được phần này:

Chi tiết điền vào khách hàng trong Trang A, sau đó trong Trang B, chúng tôi tạo một trang khác hiển thị tất cả các chi tiết khách hàng ở đó, nhấp vào nút CONFIRM sau đó POST lên Trang C.

Nhưng bạn thực sự có thể thực hiện gửi javascript trên trang B, do đó không cần nhấp chuột. Làm cho nó trở thành một trang "chuyển hướng" với một hình ảnh động đang tải và bạn đã thiết lập.


Đây là những gì chúng tôi làm bây giờ. Tôi nghĩ rằng có bất kỳ logic tốt hơn để giải quyết nó. Cảm ơn. ;)
Shiro

ya, hướng tới nhiều hơn về HTTP, nhưng tôi làm việc trong môi trường PHP, vì vậy tôi nghĩ là cả hai thẻ. Cảm ơn! Đại tá mảnh đạn.
Shiro

6

Tôi biết đây là một câu hỏi cũ, nhưng tôi có một giải pháp thay thế khác với 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();

Đoạn mã trên sử dụng jQuery để tạo thẻ biểu mẫu, nối thêm các trường ẩn dưới dạng trường bài đăng và cuối cùng gửi nó. Trang này sẽ chuyển tiếp đến trang đích của biểu mẫu với dữ liệu POST được đính kèm.

ps JavaScript & jQuery là bắt buộc cho trường hợp này. Theo đề xuất của các nhận xét về các câu trả lời khác, bạn có thể sử dụng <noscript>thẻ để tạo một biểu mẫu HTML tiêu chuẩn trong trường hợp JS bị vô hiệu hóa.


5

Có một cách hack đơn giản, sử dụng $_SESSIONvà tạo một arraytrong các giá trị được đăng và một khi bạn truy cập, File_C.phpbạn có thể sử dụng nó sau đó bạn xử lý sau khi phá hủy nó.


bạn có thể cung cấp một ví dụ nhỏ về những gì bạn có ý nghĩa?
caro

3
Hiểu biết của tôi là, Trang C là một nguồn bên ngoài, lấy các giá trị bài nhưng không phải là phiên.
Naraya Bhandari

3

Tôi biết câu hỏi được phpđịnh hướng, nhưng cách tốt nhất để chuyển hướng một POSTyêu cầu có thể là sử dụng .htaccess, tức là:

RewriteEngine on
RewriteCond %{REQUEST_URI} string_to_match_in_url
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^(.*)$ https://domain.tld/$1 [L,R=307]

Giải trình:

Theo mặc định, nếu bạn muốn chuyển hướng yêu cầu với dữ liệu POST, trình duyệt sẽ chuyển hướng yêu cầu thông qua GET với 302 redirect. Điều này cũng làm giảm tất cả dữ liệu POST liên quan đến yêu cầu . Trình duyệt thực hiện điều này như một biện pháp phòng ngừa để ngăn chặn bất kỳ việc gửi lại giao dịch POST không chủ ý.

Nhưng nếu bạn muốn chuyển hướng yêu cầu POST bằng dữ liệu của nó thì sao? Trong HTTP 1.1, có một mã trạng thái cho việc này. Mã trạng thái 307chỉ ra rằng yêu cầu phải được lặp lại với cùng phương thức và dữ liệu HTTP. Vì vậy, yêu cầu POST của bạn sẽ được lặp lại cùng với dữ liệu của nó nếu bạn sử dụng mã trạng thái này.

SRC


2

Tôi đã đối mặt với các vấn đề tương tự với Yêu cầu POST trong đó Yêu cầu GET hoạt động tốt trên phần phụ trợ của tôi mà tôi đang chuyển các biến của mình, v.v. Vấn đề nằm ở chỗ phần phụ trợ thực hiện rất nhiều chuyển hướng, không hoạt động với các phương thức tiêu đề php hoặc fopen.

Vì vậy, cách duy nhất tôi làm cho nó hoạt động là đặt một biểu mẫu ẩn và đẩy qua các giá trị bằng một lần gửi POST khi trang được tải.

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>';

1

Bạn có thể sử dụng phiên để lưu $_POSTdữ liệu, sau đó truy xuất dữ liệu đó và đặt thành $_POSTyêu cầu tiếp theo.

Người dùng gửi yêu cầu tới /denty-submission-url.php
Do:

if (session_status()!==PHP_SESSION_ACTIVE)session_start();
     $_SESSION['POST'] = $_POST;
}
header("Location: /clean-url");
exit;

Sau đó trình duyệt chuyển hướng đến và yêu cầu /clean-submission-urltừ máy chủ của bạn. Bạn sẽ có một số định tuyến nội bộ để tìm ra phải làm gì với điều này.
Khi bắt đầu yêu cầu, bạn sẽ làm:

if (session_status()!==PHP_SESSION_ACTIVE)session_start();
if (isset($_SESSION['POST'])){
    $_POST = $_SESSION['POST'];
    unset($_SESSION['POST']);
}

Bây giờ, thông qua phần còn lại của yêu cầu của bạn, bạn có thể truy cập $_POSTnhư bạn có thể theo yêu cầu đầu tiên.


Bạn có thể xử lý $_POSTdữ liệu thành một chuỗi truy vấn và chuyển nó sang trang tiếp theo theo cách đó. Nhưng sau đó, dữ liệu không thể quá lớn. Và điều này có thể không hoạt động nếu tải lên tập tin có liên quan, nhưng tôi không chắc chắn.
Sậy

0

Thử cái này:

Gửi dữ liệu và yêu cầu với tiêu đề http trong trang B để chuyển hướng đến Cổng

<?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);
?>

Tiêu đề bổ sung:

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

-1

Đây là một cách tiếp cận khác phù hợp với tôi:

nếu bạn cần chuyển hướng đến một trang web khác ( user.php) và bao gồm một biến PHP ( $user[0]):

header('Location:./user.php?u_id='.$user[0]);

hoặc là

header("Location:./user.php?u_id=$user[0]");

Những lựa chọn thay thế có nghĩa là sử dụng giao thức GET. Nó hiển thị các biến trên trình duyệt của khách hàng. OP muốn hành vi tương tự với POST thay thế.
Sergio A.

-2
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();
}

Thí dụ:

 post('url', {name: 'Johnny Bravo'});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.