Przekierowanie PHP z danymi POST

241

Przeprowadziłem badania na ten temat, a niektórzy eksperci stwierdzili, że nie jest to możliwe , dlatego chciałbym poprosić o alternatywne rozwiązanie.

Moja sytuacja:

Strona A: [checkout.php] Klient wypełnia swoje dane rozliczeniowe.

Strona B: [process.php] Wygeneruj numer faktury i zapisz dane klienta w bazie danych.

Strona C: [Thirdparty.com] Trzecia bramka płatności (TYLKO AKCEPTUJEMY DANE POCZTOWE).

Klient wypełnia swoje dane i ustawia koszyk na stronie A, a następnie POST na stronie B. Wewnątrz process.php przechowuj dane POSTed w bazie danych i generuj numer faktury. Następnie WYŚLIJ dane klienta i numer faktury do bramki płatności thirdparty.com. Problem polega na wykonaniu testu POST na stronie B. cURL jest w stanie wysłać dane na stronę C, ale problem polega na tym, że strona nie przekierowała na stronę C. Klient musi wypełnić dane karty kredytowej na stronie C.

Brama płatności strony trzeciej dała nam próbkę API, próbka to POST numer faktury wraz ze szczegółami klienta. Nie chcemy, aby system generował nadmiar niechcianych numerów faktur.

Czy jest na to jakieś rozwiązanie? Nasze obecne rozwiązanie polega na tym, że klient wypełnia szczegóły na stronie A, a następnie na stronie B tworzymy kolejną stronę pokazującą wszystkie dane klienta, na której użytkownik może kliknąć przycisk POTWIERDŹ, aby przejść do strony C.

Naszym celem jest, aby klienci musieli kliknąć tylko raz.

Mam nadzieję, że moje pytanie jest jasne :)

Shiro
źródło
nie wydaje mi się, że jest to duplikat, ponieważ mój cel jest na stronie PHP, przekazuję dane POST i przekierowuję je. cURL Nie sądzę, że można to zrobić. Poszukaj eksperta dla każdej alternatywy
Shiro,
ʜᴛᴛᴘ Kod przekierowania 308?
user2284570

Odpowiedzi:

212

Wygeneruj formularz na stronie B ze wszystkimi wymaganymi danymi i działaniami ustawionymi na stronę C i prześlij go za pomocą JavaScript przy ładowaniu strony. Twoje dane zostaną przesłane do strony C bez większych problemów dla użytkownika.

To jedyny sposób, aby to zrobić. Przekierowanie to nagłówek HTTP 303, który możesz przeczytać na http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html , ale przytoczę niektóre z nich:

Odpowiedź na żądanie można znaleźć pod innym identyfikatorem URI i POWINNA zostać pobrana przy użyciu metody GET dla tego zasobu. Ta metoda istnieje przede wszystkim w celu umożliwienia wyjściu skryptu aktywowanego POST przekierowania klienta użytkownika do wybranego zasobu. Nowy identyfikator URI nie zastępuje odwołania do pierwotnie żądanego zasobu. Odpowiedź 303 NIE MOŻE być buforowana, ale odpowiedź na drugie (przekierowane) żądanie może być buforowana.

Jedynym sposobem na osiągnięcie tego, co robisz, jest strona pośrednia, która wysyła użytkownika do strony C. Oto krótki / prosty fragment, w jaki sposób możesz to osiągnąć:

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

Powinieneś także mieć prosty formularz „potwierdź” wewnątrz tagu noscript, aby mieć pewność, że użytkownicy bez Javascript będą mogli korzystać z Twojej usługi.

Peeter
źródło
2
moim celem jest strona A -> strona C, strona B to kontroler (logika biznesowa) generujący numer faktury. Z widoku systemu jest strona A-> strona B-> strona C, ale z widoku użytkownika powinna być strona A-> strona B, nigdy nie powinny one istnieć.
Shiro,
3
@Peeter: inteligentna sugestia +1. Jedynym problemem jest to, że kiedy użytkownik na stronie C przycisk powrotu jest ponownie przesłany do strony C. Ponadto zapomniałeś zakodować $ai $bza pomocą htmlentities/htmlspecialchars, zobacz stackoverflow.com/questions/6180072/php-forward-data-post/…
Marco Demaio
8
pytanie tutaj jest co, jeśli JavaScript jest wyłączony na kliencie? Czy strona B nie przekieruje zatem na stronę C?
Imran Omar Bukhsh,
24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>wewnątrz<form>
nullability
3
languageatrybut jest przestarzała, powinno być<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");
    }
}
Eduardo Cuomo
źródło
17
Chociaż na początku wygląda to również lepiej niż zaakceptowana odpowiedź, zauważam, że nie przekierowuje do dostarczonej - $urlpo prostu zastępuje zawartość istniejącej strony zawartością $urlstrony. Co ważne , kod php na $urlstronie nie jest oceniany.
iPadDeveloper2011
@ iPadDeveloper2011, w adresie URL nie masz kodu PHP! Kod PHP jest wykonywany w SERWERZE, a nie w kliencie.
Eduardo Cuomo
1
redirect_post(), po stronie serwera, kod php, wysyła żądanie do SERWERA dla $url. Jeśli $urljest to .phpstrona, zauważam, że php nie jest analizowany - HTML jest zwracany z tagami php wciąż w nim zawartymi. Czy nie chodzi o wysyłanie danych POST do skryptu po stronie serwera?
iPadDeveloper2011 18.10.13
2
@EduardoCuomo ta metoda działa tylko z adresami absoulte, ponieważ działa fopen (): php.net/manual/en/function.fopen.php To wciąż całkiem sprytna odpowiedź.
Omn
@Onn masz rację! „To nie działa ze względnym adresem URL?” nie jest pytaniem, jest stwierdzeniem. Przepraszam za zamieszanie
Eduardo Cuomo,
25

Mam inne rozwiązanie, które to umożliwia. Wymaga, aby klient uruchomił Javascript (co moim zdaniem jest obecnie słusznym wymogiem).

Wystarczy użyć żądania AJAX na stronie A, aby przejść do generowania numeru faktury i danych klienta w tle (poprzednia strona B), a następnie po pomyślnym zwróceniu żądania z poprawnymi informacjami - wystarczy wypełnić formularz na bramce płatności (Strona C).

W ten sposób użytkownik kliknie tylko jeden przycisk i przejdzie do bramki płatności. Poniżej znajduje się pseudokod

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 (używając jQuery dla wygody, ale trywialny do stworzenia czystego 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
  }
});
MikeMurko
źródło
1
To rozwiązanie ma problem, jeśli ktoś wyłączy JavaScript na tej stronie, odświeży i prześle, przejdzie strona płatności bez zapisywania czegokolwiek. może to być luka.
caoglish
2
Następnie ustaw tylko działanie paymentForm za pomocą Javascript? Jeśli JS jest wyłączone, formularz nie zostanie przesłany.
MikeMurko,
Użytkownik wyłączający JS nie powinien powodować problemów - powodem, dla którego musimy przejść do strony B, jest prawdopodobnie wygenerowanie odcisku palca lub dodanie kodu zamówienia itp. Bez nich strona C innej firmy powinna zawieść, aw najgorszym przypadku gdy wynik wróci do nas od strony trzeciej bez kodu zamówienia, nie powinniśmy przyjmować zamówienia. Jest to ogólnie dobre rozwiązanie, jeśli JS jest akceptowalny.
Koder
19

$ _SESSION jest twoim przyjacielem, jeśli nie chcesz zadzierać z Javascriptem

Powiedzmy, że próbujesz przekazać wiadomość e-mail:

Na stronie A:

// Start the session
session_start();

// Set session variables
$_SESSION["email"] = "[email protected]";

header('Location: page_b.php');

I na stronie B:

// Start the session
session_start();

// Show me the session!  
echo "<pre>";
print_r($_SESSION);
echo "</pre>";

Aby zniszczyć sesję

unset($_SESSION['email']);
session_destroy();
Robert Sinclair
źródło
dlaczego uważasz to za mniej bezpieczne niż wersja javascript?
Adam Baranyai
1
nie, to znaczy nie w porównaniu do javascript. Ogólnie rzecz biorąc, sama $ _SESSION może być nieco mniej bezpieczna niż powiedzenie $ _SESSION + cookie, chociaż $ _SESSION jest sama w sobie dość bezpieczna. Więcej informacji tutaj: stackoverflow.com/questions/17413480/session-spoofing-php
Robert Sinclair
i jak zamknąć sesję?
Sayed Muhammad Idrees
Czy chcesz zamknąć sesję?
Ivan P.
6

Możesz pozwolić PHP wykonać test POST, ale wtedy twój php uzyska zwrot, z wszelkimi komplikacjami. Myślę, że najprościej byłoby pozwolić użytkownikowi wykonać test POST.

Więc, tak jak sugerowałeś, dostaniesz rzeczywiście tę część:

Dane do wypełnienia przez klienta na stronie A, a następnie na stronie B tworzymy kolejną stronę pokazującą wszystkie dane klienta, kliknij przycisk POTWIERDŹ, a następnie POST na stronie C.

Ale tak naprawdę możesz wykonać javascript na stronie B, więc nie ma potrzeby klikania. Zrób z niego stronę przekierowującą z animacją ładowania i gotowe.

Nanne
źródło
To właśnie robimy teraz. Myślę, że jest jakaś lepsza logika PHP do jej rozwiązania. Dzięki. ;)
Shiro,
ya, bardziej ku HTTP, ale pracuję w środowisku PHP, więc myślę, że oba są tagami. Dzięki! Płk Shrapnel.
Shiro,
6

Wiem, że to stare pytanie, ale mam jeszcze inne alternatywne rozwiązanie z 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();

Powyższy kod używa jQuery do utworzenia znacznika formularza, dodając ukryte pola jako pola post i przesyłając je w końcu. Strona zostanie przekazana do strony docelowej formularza z dołączonymi danymi POST.

ps JavaScript i jQuery są wymagane w tym przypadku. Jak sugerują komentarze do innych odpowiedzi, możesz użyć <noscript>znacznika, aby utworzyć standardowy formularz HTML na wypadek, gdyby JS został wyłączony.

Raptor
źródło
5

Istnieje prosty hack, użyj $_SESSIONi utwórz jedną arrayz opublikowanych wartości, a kiedy przejdziesz do tej opcji File_C.php, możesz jej użyć, a następnie przetworzyć, po czym ją zniszczyć.

Jeffery ThaGintoki
źródło
czy możesz podać mały przykład tego, co masz na myśli?
caro
3
Rozumiem, że strona C jest zewnętrznym źródłem, które przyjmuje wartości post, ale nie sesje.
Narayan Bhandari
3

Wiem, że pytanie jest phpzorientowane, ale POSTprawdopodobnie najlepszym sposobem na przekierowanie żądania jest .htaccess:

RewriteEngine on
RewriteCond %{REQUEST_URI} string_to_match_in_url
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^(.*)$ https://domain.tld/$1 [L,R=307]

Wyjaśnienie:

Domyślnie, jeśli chcesz przekierować żądanie z danymi POST, przeglądarka przekierowuje je za pomocą GET za pomocą 302 redirect. Spowoduje to także usunięcie wszystkich danych POST powiązanych z żądaniem . Przeglądarka robi to jako środek ostrożności, aby zapobiec niezamierzonemu ponownemu przesłaniu transakcji POST.

Ale co jeśli chcesz przekierować żądanie POST z jego danymi? W HTTP 1.1 jest do tego kod stanu.Kod stanu 307wskazuje, że żądanie należy powtórzyć przy użyciu tej samej metody HTTP i danych. Twoje żądanie POST zostanie powtórzone wraz z danymi, jeśli użyjesz tego kodu stanu.

SRC

CONvid19
źródło
2

Napotkałem podobne problemy z żądaniem POST, w którym żądanie GET działało dobrze na moim backendie, który przekazuję moje zmienne itp. Problem polega na tym, że backend wykonuje wiele przekierowań, które nie działały z metodami fopen lub php.

Tak więc jedynym sposobem, w jaki działałem, było umieszczenie ukrytego formularza i przesuwanie wartości za pomocą przesyłania POST po załadowaniu strony.

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>';
kaya
źródło
1

Możesz użyć sesji do zapisania $_POSTdanych, a następnie pobrać te dane i ustawić je $_POSTna kolejne żądanie.

Użytkownik przesyła żądanie do /dirty-submission-url.php
Wykonaj:

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

Następnie przeglądarka przekierowuje do /clean-submission-urlserwera i wysyła żądania . Będziesz miał trochę wewnętrznego routingu, aby dowiedzieć się, co z tym zrobić.
Na początku żądania wykonasz:

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

Teraz, poprzez resztę twojego żądania, możesz uzyskać dostęp $_POSTtak, jak to możliwe przy pierwszym żądaniu.

Trzcina
źródło
Możesz alternatywnie przetworzyć $_POSTdane na ciąg zapytania i w ten sposób przekazać je na kolejną stronę. Ale wtedy dane nie mogą być zbyt duże. I to prawdopodobnie nie działa, jeśli dotyczy to przesyłania plików, ale nie jestem pewien.
Reed,
0

Spróbuj tego:

Wyślij dane i poproś o nagłówek http na stronie B, aby przekierować do bramki

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

Dodatkowe nagłówki:

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
użytkownik3754884
źródło
0

Oto inne podejście, które działa dla mnie:

jeśli musisz przekierować na inną stronę internetową ( user.php) i zawiera zmienną PHP ( $user[0]):

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

lub

header("Location:./user.php?u_id=$user[0]");
Lucho
źródło
Te alternatywy mają korzystać z protokołu GET. Odsłania zmienne w przeglądarce klienta. Zamiast tego OP chciał tego samego zachowania.
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();
}

Przykład:

 post('url', {name: 'Johnny Bravo'});
njoshsn
źródło