POST 데이터로 PHP 리디렉션


241

나는이 주제에 대해 약간의 연구를했으며 불가능 하다고 말한 전문가가 있으므로 다른 해결책을 요청하고 싶습니다.

내 상황 :

페이지 A : [checkout.php] 고객이 결제 세부 정보를 작성합니다.

페이지 B : [process.php] 송장 번호를 생성하고 고객 정보를 데이터베이스에 저장하십시오.

페이지 C : [thirdparty.com] 세 번째 지불 게이트웨이 (포스트 데이터 만 수락).

고객은 세부 사항을 작성하고 페이지 A에 장바구니를 설정 한 다음 페이지 B에 POST합니다. process.php 내부에서 POST 된 데이터를 데이터베이스에 저장하고 송장 번호를 생성하십시오. 그런 다음 고객 데이터 및 송장 번호를 thirdparty.com 지불 게이트웨이에 게시하십시오. 문제는 페이지 B에서 POST를 수행하는 것입니다. cURL은 데이터를 페이지 C에 게시 할 수 있지만 페이지가 페이지 C로 리디렉션되지 않은 것입니다. 고객은 페이지 C의 신용 카드 세부 정보를 작성해야합니다.

타사 결제 게이트웨이에서 API 샘플을 제공했으며 샘플은 고객 세부 정보와 함께 인보이스 번호를 POST합니다. 시스템이 원치 않는 송장 번호를 과도하게 생성하는 것을 원하지 않습니다.

이에 대한 해결책이 있습니까? 현재 솔루션은 고객이 페이지 A에서 세부 사항을 채우는 것입니다. 그런 다음 페이지 B에서 모든 고객 세부 사항을 보여주는 다른 페이지를 작성합니다. 여기서 사용자는 확인 단추를 클릭하여 페이지 C로 POST 할 수 있습니다.

우리의 목표는 고객이 한 번만 클릭하면되는 것입니다.

내 질문이 분명하기를 바랍니다 :)


나는 이것이 중복되지 않는다고 생각한다. 내 목표는 PHP 페이지 안에 있고 POST 데이터를 전달하고 리디렉션하기 때문이다. 나는 그것이 가능하지 않다고 생각합니다. 그냥 전문가의 위해에 대한 대안 모색
시로

ʜᴛᴛᴘ 308 리디렉션 코드?
user2284570

답변:


212

모든 필수 데이터 및 조치가 페이지 C로 설정된 상태로 페이지 B에서 양식을 생성하고 페이지로드시 JavaScript로 제출하십시오. 사용자의 번거 로움없이 데이터가 페이지 C로 전송됩니다.

이것이 유일한 방법입니다. 리디렉션은 http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 에서 읽을 수있는 303 HTTP 헤더 이지만 그중 일부를 인용하겠습니다.

요청에 대한 응답은 다른 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 태그 안에 간단한 "확인"양식이 있어야합니다.


2
내 목표는 페이지 A-> 페이지 C, 페이지 B는 컨트롤러 (비즈니스 로직)가 송장 번호를 생성하는 것입니다. 시스템보기에서 페이지 A-> 페이지 B-> 페이지 C이지만 사용자보기에서 페이지 A-> 페이지 B 여야하며 페이지 B가 존재하지 않아야합니다.
시로

3
@Peeter : 똑똑한 제안 +1. 유일한 문제는 페이지 C 푸시 백 버튼을 사용자가 페이지 C.에 다시 제출 될 때 또한 당신이를 인코딩하는 것을 잊었다입니다 $a$b사용하여 htmlentities/htmlspecialchars, 참조 stackoverflow.com/questions/6180072/php-forward-data-post/...
마르코 Demaio

8
여기서 질문은 클라이언트에서 자바 스크립트가 비활성화 된 경우 어떻게됩니까? 그러면 페이지 B가 페이지 C로 리디렉션되지 않습니까?
Imran Omar Bukhsh

24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>내부<form>
무효 성

3
language속성이 있어야되지 않습니다<script type="text/javascript">...</script>
알렉스 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
처음에는 이것이 허용 된 답변보다 나아 보이지만 제공된 $urlURL로 리디렉션되지는 않습니다 . 기존 페이지의 내용을 페이지의 내용으로 바꿉니다 $url. 중요하게도$url 페이지의 PHP 코드 는 평가되지 않습니다.
iPadDeveloper2011

@ iPadDeveloper2011의 URL에 PHP 코드가 없습니다! PHP 코드는 클라이언트가 아닌 서버에서 실행됩니다.
Eduardo Cuomo

1
redirect_post(), 서버 측 PHP 코드는 서버에 대한 요청을 서버에 보냅니다 $url. (가) 경우 $urlA는 .phpHTML이 여전히에서 PHP를 태그로 반환 - 페이지, 나는 PHP는 평가되지 않습니다. POST 데이터를 서버 측 스크립트로 보내는 것이 중요하지 않습니까?
iPadDeveloper2011

2
@EduardoCuomo이 메소드는 fopen () 작동 방식 때문에 absoulte urls에서만 작동합니다. php.net/manual/en/function.fopen.php 여전히 멋진 답변입니다.
Omn

@Omn 당신이 맞아요! "상대 URL에서는 작동하지 않습니까?" 질문이 아니라 진술입니다. 혼란을 드려 죄송합니다
Eduardo Cuomo

25

이것을 가능하게하는 또 다른 해결책이 있습니다. 클라이언트가 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
  }
});

1
이 솔루션에는 문제가 있습니다. 누군가이 페이지에서 JavaScript를 끄고 새로 고치고 제출하면 아무 것도 저장하지 않고 결제 페이지로 이동합니다. 허점이 될 수 있습니다.
cooglish

2
그런 다음 Javascript로 paymentForm 조치 만 설정 하시겠습니까? JS가 비활성화되면 양식이 제출되지 않습니다.
MikeMurko

사용자가 JS를 끄면 문제가 발생하지 않아야합니다. 페이지 B로 이동해야하는 이유는 아마도 지문을 생성하거나 주문 코드를 추가하는 것입니다. 이러한 경우가 없으면 타사 페이지 C가 실패하거나 최악의 경우, 주문 코드없이 제 3 자로부터 결과가 다시 오면 주문을 수락해서는 안됩니다. JS가 수용 가능한 경우 이것은 전반적으로 좋은 솔루션입니다.
Coder

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

왜 이것이 자바 스크립트 버전보다 덜 안전하다고 생각합니까?
Adam Baranyai

1
아니요, 자바 스크립트와 비교하지 않았습니다. $ _SESSION은 그 자체로는 꽤 안전하지만 일반적으로 $ _SESSION만으로는 $ _SESSION + 쿠키보다 덜 안전 할 수 있습니다. 여기에 더 많은 정보 : stackoverflow.com/questions/17413480/session-spoofing-php
로버트 싱클레어

세션을 닫는 방법?
사예드 무하마드 이드리스

세션을 닫아야합니까?
Ivan P.

6

PHP는 POST를 할 수 있지만 PHP는 모든 종류의 합병증과 함께 리턴을 얻습니다. 실제로 가장 간단한 방법은 사용자가 POST를 수행하는 것입니다.

그래서, 당신이 제안한 종류의, 당신은 실제로이 부분을 얻을 것입니다 :

페이지 A에서 고객 채우기 세부 사항, 그런 다음 페이지 B에서 모든 고객 세부 사항을 보여주는 다른 페이지를 작성하고 확인 단추를 클릭 한 다음 페이지 C로 POST를 클릭하십시오.

그러나 실제로 B 페이지에서 자바 스크립트 제출을 수행 할 수 있으므로 클릭 할 필요가 없습니다. 로드 애니메이션이있는 "리디렉션"페이지로 설정하면 설정됩니다.


이것이 우리가 지금하는 일입니다. PHP를 더 나은 논리로 해결할 생각입니다. 감사. ;)
시로

나중에 HTTP에 대해 더 많이 알지만 PHP 환경에서 작업하므로 두 태그라고 생각합니다. 감사! 콜랩 대령.
Shiro

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 데이터가 첨부 된 양식 대상 페이지로 전달됩니다.

이 경우 ps JavaScript 및 jQuery가 필요합니다. 다른 답변의 의견에서 제안한 것처럼 <noscript>JS가 비활성화 된 경우 태그를 사용하여 표준 HTML 양식을 만들 수 있습니다.


5

간단한 해킹 이 있으며 게시 된 값을 사용 $_SESSION하고 작성 array하며 일단 사용하면 해당 값 File_C.php을 사용할 수 있습니다.


당신이 의미하는 바를 조금 보여줄 수 있습니까?
caro

3
내 이해는 페이지 C는 외부 소스이며 게시 값은 필요하지만 세션은 아닙니다.
Narayan Bhandari

3

질문이 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


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데이터를 쿼리 문자열로 처리 하여 다음 방식으로 후속 페이지에 전달할 수 있습니다. 그러나 데이터가 너무 클 수는 없습니다. 파일 업로드가 관련된 경우 아마도 작동하지 않지만 확실하지 않습니다.
Reed

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

0

여기 나를 위해 작동하는 또 다른 접근법이 있습니다.

다른 웹 페이지 ( user.php) 로 리디렉션해야 하고 PHP 변수 ( $user[0])를 포함하는 경우 :

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

또는

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

이러한 대안은 GET 프로토콜을 사용하기위한 것입니다. 클라이언트 브라우저에서 변수를 노출합니다. OP는 대신 POST와 동일한 동작을 원했습니다.
Sergio 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.