使用POST数据进行PHP重定向

Shi*_*iro 220 php post

我做了一些关于这个主题的研究,有些专家说过这是不可能的,所以我想问一个替代解决方案.

我的情况:

页面A:[checkout.php]客户填写其结算明细.

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

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

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

第三方支付网关确实给了我们API样本,样本是POST发票号和客户详细信息.我们不希望系统生成多余的不需要的发票号.

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

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

希望我的问题很明确:)

Pee*_*ter 197

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

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

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

实现您正在做的事情的唯一方法是使用将用户发送到Page 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>
Run Code Online (Sandbox Code Playgroud)

您还应该在noscript标记内部使用简单的"确认"表单,以确保没有Javascript的用户能够使用您的服务.

  • `<noscript> <input type ="submit"value ="如果没有重定向,请单击此处."/> </ noscript>`在`<form>中 (23认同)
  • 这里的问题是如果在客户端禁用Javascript怎么办?页面B不会重定向到页面C,是吗? (8认同)
  • @Peeter:聪明的建议+1.唯一的问题是,当页面C上的用户按下按钮时,会重新提交到Page C.此外,您忘记使用`htmlentities/htmlspecialchars`对`$ a`和`$ b`进行编码,请参阅http://stackoverflow.com /问题/ 6180072/PHP的正向数据员额/ 6180337#6180337 (3认同)
  • 不推荐使用`language`属性,它应该是`<script type ="text/javascript"> ... </ script>` (3认同)
  • 我的目标是在页面A - >页面C,页面B是控制器(业务逻辑)生成发票编号.从系统视图是页面A->页面B->页面C,但是从用户视图应该是页面A->页面B,它们应该永远不会释放页面B. (2认同)
  • 我很惊讶没有人这么说过,这个答案是非常糟糕的做法,应该避免。通过在页面 B 上放置此表单 - 将数据保存到数据库后,某人很可能可以操纵此数据(即使是隐藏的)。因此,最终用户可以修改价格或订单号或其他任何内容 - 您确实想尝试并避免这种情况。请参阅下面使用 $SESSION 的任何选项 - 这是一种更好的方法。 (2认同)

Edu*_*omo 33

/**
 * 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然起初这看起来也比接受的答案好,但我注意到它没有重定向到提供的`$ url` - 它只是用`$ url`页面的内容替换现有页面的内容.**重要的是**,不会评估`$ url`页面中的php代码. (17认同)
  • @EduardoCuomo这个方法只适用于absoulte url,因为fopen()的工作方式如下:http://php.net/manual/en/function.fopen.php这仍然是一个非常漂亮的答案. (2认同)

Mik*_*rko 22

我有另一个解决方案,使这成为可能.它要求客户端运行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>
Run Code Online (Sandbox Code Playgroud)

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
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是比选定的答案更好的答案! (2认同)
  • 那么只用Javascript设置paymentForm动作?如果JS被禁用,表单将不会提交. (2认同)

Rob*_*air 14

$ _SESSION是你的朋友,如果你不想搞乱Javascript,并且它的安全性稍差.

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

在第A页:

// Start the session
session_start();

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

header('Location: page_b.php');
Run Code Online (Sandbox Code Playgroud)

在页面B上:

// Start the session
session_start();

// Show me the session!  
echo "<pre>";
print_r($_SESSION);
echo "</pre>";
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个有效的选项,因为用户想要将信息发布到“Page_C”,而外部页面和“$_SESSION”将不可用。 (2认同)

Nan*_*nne 6

你可以让PHP做一个POST,但是你的php会得到回报,有各种各样的复杂情况.我认为最简单的是让用户真正做POST.

那么,你建议的那种,你会得到这个部分:

客户填写页面A中的详细信息,然后在页面B中创建另一个页面,显示所有客户详细信息,单击确认按钮,然后POST到页面C.

但你实际上可以在页面B上进行javascript提交,因此不需要点击.使用加载动画将其设为"重定向"页面,然后进行设置.


Rap*_*tor 6

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

上面的代码使用jQuery创建表单标记,将隐藏字段作为帖子字段附加,并最后提交.该页面将转发到附加了POST数据的表单目标页面.

ps这种情况需要JavaScript和jQuery.正如其他答案的评论所暗示的那样,如果<noscript>禁用JS ,您可以使用标记创建标准HTML表单.


Jef*_*oki 5

有一个简单的黑客,使用$_SESSION和创建一个array已发布的值,一旦你去了File_C.php你可以使用它然后你处理后,它会破坏它.

  • 我的理解是,Page C是一个外部源,它接受post值而不是session. (3认同)

Ree*_*eed 5

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

用户向 /dirty-submission-url.php 提交请求 执行
以下操作:

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

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

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

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


Ped*_*ito 5

我知道这个问题是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]
Run Code Online (Sandbox Code Playgroud)

解释:

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

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

资源中心


kay*_*aya 5

我在 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>';
Run Code Online (Sandbox Code Playgroud)