POSTデータを使用したPHPリダイレクト


241

私はこのトピックについていくつかの調査を行い、それは不可能であると言っている専門家が何人かいるので、別の解決策を求めたいと思います。

私の状況:

ページA:[checkout.php]お客様が請求の詳細を入力します。

ページB:[process.php]請求書番号を生成し、データベースに顧客の詳細を保存します。

ページC:[thirdparty.com] 3番目の支払いゲートウェイ(投稿データのみを受け入れる)。

顧客は詳細を入力してカートをページAに設定し、次にページBにPOSTします。process.php内で、POSTされたデータをデータベース内に保存し、請求書番号を生成します。その後、顧客データと請求書番号をthirdparty.com支払いゲートウェイにPOSTします。問題はページBでPOSTを実行しています。cURLはページCにデータをPOSTできますが、問題はページがページCにリダイレクトされなかったことです。お客様はページCでクレジットカードの詳細を入力する必要があります。

サードパーティの支払いゲートウェイからAPIサンプルが提供されました。サンプルは、請求書番号と顧客詳細をPOSTしたものです。システムで不要な請求書番号が過剰に生成されることは望ましくありません。

これに対する解決策はありますか?私たちの現在のソリューションは、お客様がページAに詳細を入力することです。次に、ページBに別のページを作成し、そこにすべてのお客様の詳細を表示します。ユーザーは[確認]ボタンをクリックしてページCにPOSTできます。

私たちの目標は、お客様が一度だけクリックする必要があることです。

私の質問が明確であることを願っています:)


私はこれが重複しているとは思わない、それは私の目標がPHPページ内にあり、POSTデータを渡してリダイレクトするためです。cURL可能ではないと思います。代わりにエキスパートを探してください
Shiro

308 308リダイレクトコード?
user2284570

回答:


212

必要なすべてのデータとアクションをページCに設定して、ページBにフォームを生成し、ページのロード時にJavaScriptで送信します。あなたのデータはユーザーにそれほど面倒なしでページCに送られます。

これが唯一の方法です。リダイレクトは303 HTTPヘッダーであり、http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.htmlで読み取ることができますが、その一部を引用します。

リクエストへの応答は別のURIで見つけることができ、そのリソースでGETメソッドを使用して取得する必要があります。このメソッドは主に、POSTでアクティブ化されたスクリプトの出力がユーザーエージェントを選択したリソースにリダイレクトできるようにするために存在します。新しいURIは、最初に要求されたリソースの代替参照ではありません。303応答はキャッシュしてはなりません(MUST NOT)が、2番目の(リダイレクトされた)要求への応答はキャッシュ可能である可能性があります。

あなたがやっていることを達成する唯一の方法は、ユーザーをページ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>

また、JavaScriptを持たないユーザーがサービスを使用できるようにするために、noscriptタグ内に単純な「確認」フォームが必要です。


2
私の目標はページA->ページC、ページBは請求書番号を生成するコントローラー(ビジネスロジック)です。システムビューからはページA->ページB->ページCですが、ユーザービューからはページA->ページBである必要があり、ページBが存在することを決して解放しないでください。
シロ

3
@ピーター:スマートな提案+1。唯一の問題は、ページCのプッシュバックボタンのユーザーがページCに再送信されることです。さらに、をエンコードするのを忘れて、$a$b使用してhtmlentities/htmlspecialcharsstackoverflow.com
questions / 6180072 / php

8
ここでの質問は、クライアントでJavascriptが無効になっている場合はどうなりますか?ページBはページCにリダイレクトしませんか?
Imran Omar Bukhsh

24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>内部<form>
nullability 2013年

3
このlanguage属性は非推奨です。それは適切である必要があります<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
最初はこれも受け入れられた回答よりもよく見えますが、指定された$urlページにリダイレクトされないことに注意してください-既存のページのコンテンツをページのコンテンツで置き換えるだけ$urlです。 重要なのは、$urlページのphpコードが評価されないことです。
iPadDeveloper2011 2013年

@ iPadDeveloper2011、URLにはPHPコードがありません!PHPコードは、クライアントではなくサーバーで実行されます。
Eduardo Cuomo

1
redirect_post()サーバー側であるphpコードは、サーバーにリクエストを送信します$url$url.phpページの場合、phpは評価されないことに注意してください。htmlは、phpタグが含まれたまま返されます。POSTデータをサーバー側のスクリプトに送信するのが目的ではありませんか?
iPadDeveloper2011 2013年

2
この方法@EduardoCuomoためだけでfopen()でどのように動作するかを、absoulteのURLで動作します:php.net/manual/en/function.fopen.phpは、 それはまだかなり気の利いた答えです。
2013年

@Omnあなたは正しい!「これは相対URLでは機能しませんか?」質問ではなく、声明です。混乱して申し訳ありません
Eduardo Cuomo

25

これを可能にする別の解決策があります。それはクライアントがJavascriptを実行していることを必要とします(これは最近の公正な要件だと思います)。

ページAでAJAXリクエストを使用してバックグラウンドで請求書番号と顧客の詳細(前のページB)を生成し、リクエストが正しい情報で正常に返されたら、支払いゲートウェイへのフォーム送信を完了するだけです。 (ページC)。

これにより、ユーザーが1つのボタンをクリックするだけで支払いゲートウェイに進むという結果が得られます。以下はいくつかの擬似コードです

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

1
このソリューションには問題があります。誰かがこのページでJavaScriptをオフにし、更新して送信すると、何も保存されずに支払いページに移動します。これは抜け穴になる可能性があります。
caoglish 2014

2
次に、JavaScriptでpaymentFormアクションのみを設定しますか?JSが無効になっている場合、フォームは送信されません。
MikeMurko 2014

ユーザーがJSをオフにしても問題は発生しません。ページBに移動しなければならない理由は、おそらくフィンガープリントの生成や注文コードの追加などです。これらがないと、サードパーティのページCが失敗するか、最悪の場合、結果が注文コードなしでサードパーティから返された場合、注文を受け付けるべきではありません。JSが受け入れられる場合、これは全体的に良い解決策です。
コーダー、2017年

19

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バージョンよりも安全性が低いと思うのはなぜですか?
Adam Baranyai

1
いいえ、私はjavascriptと比較しないことを意味します。一般的に、$ _ SESSION自体はかなり安全ですが、$ _ SESSIONだけでは$ _SESSION + cookieと言うよりも少し安全性が低くなる可能性があります。詳細はこちら:stackoverflow.com/questions/17413480/session-spoofing-php
Robert Sinclair

そしてセッションを閉じる方法は?
ムハンマドイドリース、

セッションを閉じる必要がありますか?
Ivan P.

6

PHPにPOSTを実行させることはできますが、その後、PHPはあらゆる種類の複雑さを伴って戻ります。ユーザーにPOSTを実行させるのが最も簡単だと思います。

だから、あなたが提案したようなもので、あなたは実際にこの部分を得るでしょう:

顧客はページAで詳細を入力し、次にページBで別のページを作成してそこにすべての顧客の詳細を表示し、[確認]ボタンをクリックして、ページCにPOSTします。

ただし、ページBで実際にJavaScript送信を実行できるため、クリックする必要はありません。読み込みアニメーションを含む「リダイレクト」ページを作成すると、設定が完了します。


これが現在行っていることです。私はそれを解決するためのPHPのより良いロジックがあると考えています。ありがとう。;)
四郎

ええと、HTTPの方が好きですが、私はPHP環境で働いているので、どちらもタグだと思います。ありがとう!爆弾大佐。
シロ

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データが添付されたフォームターゲットページに転送されます。

この場合、JavaScriptおよびjQueryが必要です。他の回答のコメントで示唆されているように、<noscript>JSが無効になっている場合は、タグを使用して標準のHTMLフォームを作成できます。


5

単純なハックがあり、投稿された値を使用$_SESSIONして作成しarrayます。アクセスしFile_C.phpたら、それを使用できます。その後、破棄してから処理します。


あなたが意味することの小さな例を提供できますか?
caro

3
私の理解では、ページCは外部ソースであり、ポスト値を取得しますがセッションは取得しません。
Narayan Bhandari 2017

3

私は質問が正しいことを認識していますがphpPOSTリクエストをリダイレクトする最良の方法はおそらくを使用することです.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 withを使用してリクエストをリダイレクトし302 redirectます。これにより、リクエストに関連付けられたすべてのPOSTデータも削除されます。ブラウザは、POSTトランザクションの意図しない再送信を防ぐための予防策としてこれを行います。

しかし、とにかくPOSTリクエストをそのデータでリダイレクトしたい場合はどうでしょうか?HTTP 1.1では、このためのステータスコードがあります。ステータスコード307、同じHTTPメソッドとデータを使用してリクエストを繰り返す必要があることを示しています。したがって、このステータスコードを使用すると、POSTリクエストがデータとともに繰り返されます。

SRC


2

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

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、最初のリクエストのときと同じようにアクセスできます。


あるいは、$_POSTデータをクエリ文字列に処理し、それを次のページに渡すこともできます。しかし、その場合、データが非常に大きくなることはありません。ファイルのアップロードが関係している場合、これはおそらく機能しませんが、よくわかりません。
リード

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

-1

ここに私のために働く別のアプローチがあります:

別のWebページ(user.php)にリダイレクトする必要があり、PHP変数($user[0])が含まれている場合:

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

または

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

これらの代替手段は、GETプロトコルを使用するためのものです。クライアントのブラウザで変数を公開します。OPは代わりにPOSTで同じ動作を望んでいました。
セルジオ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();
}

例:

 post('url', {name: 'Johnny Bravo'});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.