使用POST数据进行PHP重定向

时间:2011-04-07 05:54:20

标签: php post

我对这个主题进行过一些研究,有些专家说它不是possible,所以我想问一个替代解决方案。

我的情况:

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

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

希望我的问题很明确:)

13 个答案:

答案 0 :(得分:189)

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

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

  

对请求的响应可以是   在不同的URI下找到并且应该   使用GET方法检索   那资源。这种方法存在   主要是为了允许输出a   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>

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

答案 1 :(得分:32)

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

答案 2 :(得分:21)

我有另一种解决方案可以实现这一目标。它要求客户端运行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
  }
});

答案 3 :(得分:12)

$ _ SESSION是你的朋友,如果你不想搞乱Javascript,并且可以安全一点。

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

在第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>";

答案 4 :(得分:6)

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

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

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

但你可以在B页上实际进行javascript提交,因此无需点击。将其设为带有加载动画的“重定向”页面,然后进行设置。

答案 5 :(得分: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();

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

P.S。 JavaScript&amp;这种情况需要jQuery。正如其他答案的评论所建议的那样,如果禁用JS,您可以使用<noscript>标签创建标准HTML表单。

答案 6 :(得分:5)

有一个简单的黑客攻击,使用$_SESSION并创建array个已发布的值,一旦你转到File_C.php你就可以使用它然后在那个毁灭后进行处理它

答案 7 :(得分:4)

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

答案 8 :(得分:2)

我知道问题是面向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数据重定向请求,浏览器会使用302 redirect通过GET重定向请求。 这还会删除所有与请求关联的POST数据。浏览器这样做是为了防止任何无意的重新提交POST事务。

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

SRC

答案 9 :(得分:1)

您可以使用会话来保存$_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

答案 10 :(得分:0)

尝试一下:

发送数据并请求页面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

答案 11 :(得分:0)

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

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

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

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

答案 12 :(得分:-1)

<div class="right">
  <div class="tel-no">
    <img src="http://www.encorediamond.co.uk/skin/frontend/ecd/default/images/common/telephone-icon.fw.png" alt="telephone-icon">
    <p><span>015395 67957</span>

    </p>
  </div>
  <div class="cart1">
    <a href="#header-cart" class="toggle-minicart skip-link skip-cart">
      <!--<img src="" alt="cart-icon">
                    <span class="cart-label">5</span>-->


      <img src="http://www.encorediamond.co.uk/skin/frontend/ecd/default/images/common/cart-icon.fw.png" alt="cart-icon">
      <span class="cart-label">
                        0                    </span>
    </a>

  </div>
  <div class="col-lg-4 col-md-5 col-sm-5 col-xs-12 top-cart" style="display: none">
    <div class="header-minicart">
      <a href="#header-cart" class="skip-link skip-cart  no-count">
        <!--<span class="icon"></span>
    <span class="label"> ( </span>
    <span class="count"> )</span>-->
      </a>

      <div id="header-cart" class="block block-cart skip-content">
        <div id="minicart-error-message" class="minicart-message"></div>
        <div id="minicart-success-message" class="minicart-message"></div>
        <div class="minicart-wrapper">
          <p class="block-subtitle">Recently added item(s) <a class="close skip-link-close" href="#" title="Close">×</a>

          </p>
          <p class="empty">You have no items in your shopping cart.</p>
        </div>
      </div>
    </div>
  </div>
  <form id="search_mini_form" action="http://www.encorediamond.co.uk/catalogsearch/result/" method="get">
    <div class="header-search-form">
      <input kl_virtual_keyboard_secure_input="on" autocomplete="off" id="search" name="q" value="" class="input-text" maxlength="128" type="text">
      <button type="submit" title="Search" class="button"></button>
      <div style="display: none;" id="search_autocomplete" class="search-autocomplete"></div>
      <script type="text/javascript">
        //<![CDATA[
        var searchForm = new Varien.searchForm('search_mini_form', 'search', '');
        searchForm.initAutocomplete('http://www.encorediamond.co.uk/catalogsearch/ajax/suggest/', 'search_autocomplete');
         //]]>
      </script>
    </div>
  </form>
  <!-- <div class="navbar-toggle collapsed mobile-expand" data-toggle="collapse" data-target=".navbar-collapse"></div>--></div>

示例:

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