繁体   English   中英

使用 POST 数据进行 PHP 重定向

[英]PHP Redirect with POST data

我对这个话题做了一些研究,有一些专家说不可能,所以我想寻求一个替代的解决方案。

我的情况:

页面 A:[checkout.php] 客户填写他们的账单详情。

页面 B:[process.php] 生成发票编号并将客户详细信息存储在数据库中。

页面 C:[thirdparty.com] 第三支付网关(仅接受发布数据)。

客户填写他们的详细信息并在页面 A 中设置他们的购物车,然后 POST 到页面 B。在 process.php 中,将 POST 数据存储在数据库中并生成发票编号。 之后,将客户数据和发票编号发布到 thirdparty.com 支付网关。 问题是在页面 B 中进行 POST。cURL 能够将数据 POST 到页面 C,但问题是页面没有重定向到页面 C。客户需要在页面 C 上填写信用卡详细信息。

第三方支付网关确实给了我们 API 示例,该示例是 POST 发票编号和客户详细信息。 我们不希望系统生成过多的不需要的发票编号。

有什么解决办法吗? 我们目前的解决方案是让客户在页面 A 中填写详细信息,然后在页面 B 中创建另一个页面,显示那里的所有客户详细信息,用户可以在其中单击确认按钮以 POST 到页面 C。

我们的目标是让客户只需点击一次。

希望我的问题很清楚:)

在页面 B 上生成一个表单,将所有必需的数据和操作设置为页面 C,并在页面加载时使用 JavaScript 提交它。 您的数据将被发送到页面 C,而不会给用户带来太多麻烦。

这是唯一的方法。 重定向是一个 303 HTTP 标头,您可以在http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html上阅读它,但我会引用其中的一些内容:

可以在不同的 URI 下找到对请求的响应,并且应该使用该资源上的 GET 方法来检索。 此方法的存在主要是为了允许 POST 激活脚本的输出将用户代理重定向到选定的资源。 新的 URI 不是原始请求资源的替代引用。 303 响应不能被缓存,但对第二个(重定向)请求的响应可能是可缓存的。

实现您正在做的事情的唯一方法是使用将用户发送到页面 C 的中间页面。这是一个关于如何实现这一目标的小/简单片段:

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

您还应该在 noscript 标记内有一个简单的“确认”表单,以确保没有 Javascript 的用户能够使用您的服务。

/**
  * 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");
  }
}

如果您不想弄乱 Javascript,$_SESSION 是您的朋友

假设您正在尝试传递电子邮件:

在 A 页:

// Start the session
session_start();

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

header('Location: page_b.php');

在 B 页上:

// Start the session
session_start();

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

销毁会话

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

我有另一个解决方案可以做到这一点。 它要求客户端运行 Javascript(我认为这些天这是一个公平的要求)。

只需在页面 A 上使用 AJAX 请求即可在后台(您之前的页面 B)中生成您的发票编号和客户详细信息,然后在请求成功返回并包含正确信息后 - 只需将表单提交到您的支付网关(C 页)。

这将实现用户只需单击一个按钮并进入支付网关的结果。 下面是一些伪代码

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(为了方便而使用 jQuery,但制作纯 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
  }
});

我知道这是一个老问题,但我还有另一个使用 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();

上面的代码使用jQuery创建了一个表单标签,将隐藏字段附加为post字段,最后提交。 该页面将转发到附加了 POST 数据的表单目标页面。

ps 在这种情况下需要 JavaScript 和 jQuery。 正如其他答案的评论所建议的那样,您可以使用<noscript>标记来创建标准的 HTML 表单,以防 JS 被禁用。

我知道这个问题是面向php的,但是重定向POST请求的最佳方法可能是使用.htaccess ,即:

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

解释:

默认情况下,如果您想使用 POST 数据重定向请求,浏览器会通过 GET 使用302 redirect将其重定向。 这也会删除与请求关联的所有 POST 数据 浏览器这样做是为了防止意外重新提交 POST 交易。

但是如果你想用它的数据重定向 POST 请求怎么办? 在 HTTP 1.1 中,有一个状态码。 状态码307表示应使用相同的 HTTP 方法和数据重复请求 因此,如果您使用此状态代码,您的 POST 请求将与它的数据一起重复。

SRC

您可以让 PHP 进行 POST,但随后您的 php 将获得回报,并带来各种复杂情况。 我认为最简单的方法是让用户进行 POST。

所以,就像你建议的那样,你确实会得到这部分:

客户在页面 A 中填写详细信息,然后在页面 B 中我们创建另一个页面,在那里显示所有客户详细信息,单击确认按钮,然后发布到页面 C。

但是您实际上可以在页面 B 上进行 javascript 提交,因此无需单击。 让它成为一个带有加载动画的“重定向”页面,然后你就设置好了。

有一个简单的技巧,使用$_SESSION并创建一个发布值的array ,一旦你进入File_C.php你就可以使用它,然后在销毁它之后进行处理。

我在 POST 请求中遇到了类似的问题,其中 GET 请求在我的后端工作正常,我正在传递我的变量等。问题在于后端做了很多重定向,这不适用于 fopen 或 php 标头方法。

所以我让它工作的唯一方法是放置一个隐藏的表单并在页面加载时使用 POST 提交推送值。

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

您可以使用会话保存$_POST数据,然后检索该数据并在后续请求中将其设置为$_POST

用户向 /dirty-submission-url.php 提交请求
做:

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

然后浏览器重定向到并从您的服务器请求/clean-submission-url 您将有一些内部路由来弄清楚如何处理它。
在请求开始时,您将执行以下操作:

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

现在,通过您的其余请求,您可以像在第一个请求时一样访问$_POST

尝试这个:

在页面 B 中使用 http 标头发送数据和请求以重定向到网关

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

附加标题:

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

例子:

 post('url', {name: 'Johnny Bravo'});

这里还有另一种对我有用的方法:

如果您需要重定向到另一个网页( user.php )并包含一个 PHP 变量( $user[0] ):

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

或者

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM