PHP - 通过POST方式重定向并发送数据

51
我有一个在线网关,需要提交带有隐藏字段的HTML表单。我需要通过PHP脚本完成此操作,而无需任何HTML表单(我在数据库中拥有隐藏字段的数据)。
要使用GET方法发送数据:
header('Location: http://www.provider.com/process.jsp?id=12345&name=John');

那么要通过POST方法发送数据应该怎么做呢?

14个回答

46

使用PHP无法完成此操作。

正如其他人所说,您可以使用cURL - 但PHP代码成为客户端而不是浏览器。

如果必须使用POST,则唯一的方法是使用PHP生成填充的表单,并使用window.onload钩子调用JavaScript提交表单。


3
很奇怪,cURL 不是解决方案,因为我自己曾经使用它来做完全相同的事情。不过,我猜你的解决方案也可以。 - Arto Uusikangas
2
您可以使用jQuery $.post方法。在这种情况下,您可以选择在提交时保留在此网站上还是重定向。 - Ervin
是的,可以使用PHP和curl代理请求并将其转换为POST - 但这意味着接收端容易受到CSRF攻击和/或未对请求应用基于会话的控制(您可以在传递给curl的参数中模拟其中一些,但不是全部)。 - symcbean
  1. 2015年对308重定向的支持非常有限。
  2. 永久重定向几乎总是解决问题的错误答案。
- symcbean
http://mentaljetsam.wordpress.com/2008/06/02/using-javascript-to-post-data-between-pages/ - Stefan

39

这是解决方法的示例。

function redirect_post($url, array $data)
{
    ?>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script type="text/javascript">
            function closethisasap() {
                document.forms["redirectpost"].submit();
            }
        </script>
    </head>
    <body onload="closethisasap();">
    <form name="redirectpost" method="post" action="<? echo $url; ?>">
        <?php
        if ( !is_null($data) ) {
            foreach ($data as $k => $v) {
                echo '<input type="hidden" name="' . $k . '" value="' . $v . '"> ';
            }
        }
        ?>
    </form>
    </body>
    </html>
    <?php
    exit;
}

1
这是一个“不太优雅”的解决方案,但绝对有效!我创建了一个类似的函数,但使用显式的 echo 代替关闭和重新打开 <? ?> 标签。 - DiegoDD
我喜欢这种有点"脏"的东西。 可能需要将 PHP 标签设置为 <?php。 - aiternal
@DiegoDD:你有任何代码/代码片段可以分享给我吗,这样我就可以复制了吗? - Hiep
1
@Hiep 这是您需要的链接:https://gist.github.com/yphastos/a1809b654de9702811d3a09a66cf82a3 - DiegoDD
肮脏但好用的解决方案 - Javid Karimov
这是一个非常棒的“gambiarra”,正如我们在巴西所称赞的那样。我喜欢它。 - Programmeur Désespéré

12

一个更好、更整洁的解决方案是使用 $_SESSION:

使用 session:

$_SESSION['POST'] = $_POST;

用于重定向头请求,请使用:

header('Location: http://www.provider.com/process.jsp?id=12345&name=John', true, 307;)

307是可用于重定向请求的http_response_code,并且可以携带提交的POST值。


2
谢谢。你的解决方案是最好的。 - Mykhailo YATSYSHYN

11

如果您想避免使用curl调用并使浏览器像正常情况下重定向并模拟POST调用,则可以使用另一种解决方案:

保存帖子并进行临时重定向:

function post_redirect($url) {
    $_SESSION['post_data'] = $_POST;
    header('Location: ' . $url);
}

然后始终检查会话变量post_data

if (isset($_SESSION['post_data'])) {
    $_POST = $_SESSION['post_data'];
    $_SERVER['REQUEST_METHOD'] = 'POST';
    unset($_SESSION['post_data']);
}

会有一些缺失的组件,例如apache_request_headers()将不会显示POST Content头等。


3
感谢您提供最干净的“脏”解决方案。 - Gregzenegair

7

这将涉及到cURL PHP扩展。

$ch = curl_init('http://www.provider.com/process.jsp');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "id=12345&name=John");
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);  // RETURN THE CONTENTS OF THE CALL
$resp = curl_exec($ch);

1
嘿,马特,使用CURL是不可能的。通过curl我们无法进行重定向。 - rahul
@rahul,curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);不能解决这个问题吗? - Typewar
根据我的经验,在Laravel控制器中CURLOPT_FOLLOWLOCATION无法正常工作。 - Eugene van der Merwe

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

我是PHP的新手。有没有办法用它改变URL?这个函数不会改变URL,但会重定向。我将$headers保留为null(我应该吗?)。 - Michael Yaworski

2
使用curl来实现。在Google搜索“curl php post”即可找到以下内容:http://www.askapache.com/htaccess/sending-post-form-data-with-php-curl.html
需要注意的是,你也可以使用数组作为CURLOPT_POSTFIELDS选项的值。从php.net文档中可知:
完整的数据用于执行HTTP “POST”操作。要上传文件,请在文件名前添加@并使用完整路径。这可以作为urlencode字符串传递,例如:“para1=val1&para2=val2&...”,或将其作为以字段名称为键和字段数据为值的数组传递。如果值是数组,则Content-Type标头将设置为multipart/form-data。

1

1
你需要使用fsockopen打开一个套接字并模拟HTTP-Post请求。谷歌会显示许多代码片段来帮助你模拟请求。

1

或者,在重定向之前设置一个会话变量,并在目标 URL 中测试它,可以为我解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接