Redirect PHP dengan data POST

241

Saya melakukan riset tentang topik ini, dan ada beberapa ahli yang mengatakan bahwa itu tidak mungkin , jadi saya ingin meminta solusi alternatif.

Situasi saya:

Halaman A: [checkout.php] Pelanggan mengisi rincian tagihan mereka.

Halaman B: [process.php] Menghasilkan nomor faktur dan menyimpan detail pelanggan dalam database.

Halaman C: [thirdparty.com] Gateway Pembayaran Ketiga (HANYA MENERIMA DATA POST).

Pelanggan mengisi rincian mereka dan mengatur keranjang mereka di Halaman A, kemudian POST ke Halaman B. Di dalam process.php, simpan data POST di dalam basis data dan buat nomor faktur. Setelah itu, POSTkan data pelanggan dan nomor faktur ke gateway pembayaran thirdparty.com. Masalahnya adalah melakukan POST di halaman B. cURL dapat mengirim data ke Halaman C, tetapi masalahnya adalah halaman tidak dialihkan ke halaman C. Pelanggan harus mengisi rincian Kartu Kredit pada Halaman C.

Gateway pembayaran pihak ketiga memberi kami sampel API, sampel POST nomor faktur bersama dengan detail pelanggan. Kami tidak ingin sistem menghasilkan kelebihan jumlah faktur yang tidak diinginkan.

Apakah ada solusi untuk ini? Solusi kami saat ini adalah agar pelanggan mengisi detail di Halaman A, lalu di Halaman B kami membuat halaman lain yang menunjukkan semua detail pelanggan di sana, di mana pengguna dapat mengklik tombol CONFIRM untuk POST ke Halaman C.

Tujuan kami adalah agar pelanggan hanya perlu mengklik sekali.

Semoga pertanyaan saya jelas :)

Shiro
sumber
Saya tidak berpikir ini duplikat untuk ini, itu karena tujuan saya ada di dalam halaman PHP, meneruskan data POST dan mengarahkannya kembali. CURL Saya rasa tidak mungkin melakukannya. Hanya mencari ahli alternatif apa pun untuk itu
Shiro
ʜᴛᴛᴘ 308 kode pengalihan?
user2284570

Jawaban:

212

Buat formulir di Halaman B dengan semua data dan tindakan yang diperlukan diatur ke Halaman C dan kirimkan dengan JavaScript di pemuatan halaman. Data Anda akan dikirim ke Halaman C tanpa banyak kesulitan bagi pengguna.

Ini satu-satunya cara untuk melakukannya. Arahan ulang adalah tajuk HTTP 303 yang dapat Anda baca di http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html , tetapi saya akan mengutip beberapa di antaranya:

Respons terhadap permintaan dapat ditemukan di bawah URI yang berbeda dan HARUS diambil menggunakan metode GET pada sumber daya itu. Metode ini ada terutama untuk memungkinkan output dari skrip yang diaktifkan POST untuk mengarahkan agen pengguna ke sumber daya yang dipilih. URI baru bukan referensi pengganti untuk sumber daya yang diminta semula. Respons 303 TIDAK HARUS di-cache, tetapi respons terhadap permintaan kedua (dialihkan) mungkin dapat di-cache.

Satu-satunya cara untuk mencapai apa yang Anda lakukan adalah dengan laman perantara yang mengirim pengguna ke Halaman C. Berikut cuplikan kecil / sederhana tentang cara Anda dapat mencapainya:

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

Anda juga harus memiliki formulir "konfirmasi" sederhana di dalam tag noscript untuk memastikan pengguna tanpa Javascript akan dapat menggunakan layanan Anda.

Peeter
sumber
2
tujuan saya ada di Halaman A -> Halaman C, Halaman B adalah controller (business logic) menghasilkan nomor faktur. Dari tampilan sistem adalah Halaman A-> Halaman B-> Halaman C, tetapi dari tampilan pengguna harus Halaman A-> Halaman B, mereka tidak boleh melepaskan Halaman B yang ada.
Shiro
3
@Peeter: saran cerdas +1. Satu-satunya masalah adalah bahwa ketika pengguna pada tombol tekan kembali halaman C diajukan kembali ke Halaman C. Selain itu Anda lupa untuk menyandikan $adan $bdengan menggunakan htmlentities/htmlspecialchars, lihat stackoverflow.com/questions/6180072/php-forward-data-post/…
Marco Demaio
8
pertanyaan di sini adalah bagaimana jika Javascript dinonaktifkan pada klien? Halaman B tidak akan mengalihkan ke halaman C, kan?
Imran Omar Bukhsh
24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>di dalam<form>
nullability
3
yang languageatribut usang, harus<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
sumber
17
Meskipun pada awalnya ini juga terlihat lebih baik daripada jawaban yang diterima, saya perhatikan bahwa itu tidak mengarahkan ke yang disediakan - $urlItu hanya mengganti konten halaman yang ada dengan konten $urlhalaman. Yang penting , kode php di $urlhalaman tidak dievaluasi.
iPadDeveloper2011
@ iPadDeveloper2011, di URL, Anda tidak memiliki kode PHP! Kode PHP dieksekusi di SERVER, bukan di klien.
Eduardo Cuomo
1
redirect_post(), yang merupakan sisi server, kode php, mengirimkan permintaan ke SERVER untuk a $url. Jika halaman $urladalah .php, saya perhatikan bahwa php tidak dievaluasi - html dikembalikan dengan tag php masih di dalamnya. Bukankah seluruh titik untuk mengirim data POST ke skrip sisi server?
iPadDeveloper2011
2
@EduardoCuomo metode ini hanya berfungsi dengan url absoulte, karena cara kerja fopen (): php.net/manual/en/function.fopen.php Ini masih merupakan jawaban yang cukup bagus.
Omn
@Om, kamu benar! "Ini tidak berfungsi dengan URL relatif?" bukan pertanyaan, adalah pernyataan. Maaf atas kebingungan
Eduardo Cuomo
25

Saya punya solusi lain yang memungkinkan ini terjadi. Ini mengharuskan klien menjalankan Javascript (yang saya pikir merupakan persyaratan yang adil hari ini).

Cukup gunakan permintaan AJAX di Halaman A untuk membuka dan menghasilkan nomor faktur dan detail pelanggan Anda di latar belakang (Halaman B Anda sebelumnya), lalu setelah permintaan berhasil dikembalikan dengan informasi yang benar - cukup isi formulir pengiriman ke gateway pembayaran Anda (Halaman C).

Ini akan mencapai hasil Anda dari pengguna hanya mengklik satu tombol dan melanjutkan ke gateway pembayaran. Di bawah ini adalah beberapa kodesemu

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 (menggunakan jQuery untuk kenyamanan tetapi sepele untuk membuat Javascript murni):

$('#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
sumber
1
Solusi ini memiliki masalah, jika seseorang mematikan JavaScript di halaman ini, lakukan refresh, dan kirimkan, itu akan pergi halaman pembayaran tanpa menyimpan apa pun. ini bisa menjadi celah.
caoglish
2
Maka hanya setel tindakan pembayaran ke Javascript? Jika JS dinonaktifkan, formulir tidak akan dikirimkan.
MikeMurko
Pengguna mematikan JS seharusnya tidak menyebabkan masalah bagi kami - alasan kami harus membuka Halaman B mungkin adalah untuk menghasilkan sidik jari atau menambahkan kode pesanan, dll. Tanpa ini maka halaman pihak ketiga C harus gagal, atau paling buruk, ketika hasilnya kembali kepada kami dari pihak ke-3 tanpa kode pesanan, kami tidak boleh menerima pesanan. Ini secara keseluruhan merupakan solusi yang baik jika JS dapat diterima.
Coder
19

$ _SESSION adalah teman Anda jika Anda tidak ingin mengacaukan Javascript

Katakanlah Anda mencoba mengirim email:

Di halaman A:

// Start the session
session_start();

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

header('Location: page_b.php');

Dan di Halaman B:

// Start the session
session_start();

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

Untuk menghancurkan sesi

unset($_SESSION['email']);
session_destroy();
Robert Sinclair
sumber
mengapa Anda menganggap ini kurang aman daripada versi javascript?
Adam Baranyai
1
tidak, maksud saya tidak dibandingkan dengan javascript. Secara umum $ _SESSION saja bisa menjadi sedikit kurang aman daripada mengatakan $ _SESSION + cookie, meskipun $ _SESSION cukup aman dengan sendirinya. Info lebih lanjut di sini: stackoverflow.com/questions/17413480/session-spoofing-php
Robert Sinclair
dan bagaimana cara menutup sesi?
Sayed Muhammad Idrees
Apakah Anda perlu menutup sesi?
Ivan P.
6

Anda dapat membiarkan PHP melakukan POST, tetapi kemudian php Anda akan mendapatkan pengembaliannya, dengan segala macam komplikasi. Saya pikir yang paling sederhana adalah membiarkan pengguna melakukan POST.

Jadi, seperti apa yang Anda sarankan, Anda akan mendapatkan bagian ini:

Pelanggan mengisi detail di Halaman A, lalu di Halaman B kami membuat halaman lain menunjukkan semua detail pelanggan di sana, klik tombol CONFIRM kemudian POST ke Halaman C.

Tetapi Anda benar-benar dapat melakukan pengiriman javascript di halaman B, jadi tidak perlu klik. Jadikan itu halaman "redirect" dengan animasi memuat, dan Anda sudah siap.

Nanne
sumber
Inilah yang kami lakukan sekarang. Saya berpikir apakah ada logika PHP yang lebih baik untuk menyelesaikannya. Terima kasih. ;)
Shiro
ya, lebih ke arah HTTP, tapi saya bekerja di lingkungan PHP, jadi saya pikir keduanya adalah tag. Terima kasih! Kolonel pecahan peluru.
Shiro
6

Saya tahu ini adalah pertanyaan lama, tapi saya punya solusi alternatif lain dengan 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();

Kode di atas menggunakan jQuery untuk membuat tag formulir, menambahkan bidang tersembunyi sebagai bidang posting, dan mengirimkannya pada akhirnya. Halaman akan meneruskan ke halaman target formulir dengan data POST terlampir.

ps JavaScript & jQuery diperlukan untuk kasus ini. Seperti yang disarankan oleh komentar dari jawaban lain, Anda dapat menggunakan <noscript>tag untuk membuat formulir HTML standar jika JS dinonaktifkan.

Raptor
sumber
5

Ada peretasan sederhana, gunakan $_SESSIONdan buat salah satu arraydari nilai yang diposting, dan sekali Anda pergi ke File_C.phpAnda dapat menggunakannya lalu lakukan proses setelah itu hancurkan.

Jeffery ThaGintoki
sumber
dapatkah Anda memberikan sedikit contoh tentang maksud Anda?
caro
3
Pemahaman saya adalah, Halaman C adalah sumber eksternal, yang mengambil nilai posting tetapi bukan sesi.
Narayan Bhandari
3

Saya menyadari bahwa pertanyaannya phpberorientasi, tetapi cara terbaik untuk mengarahkan kembali suatu POSTpermintaan mungkin menggunakan .htaccess, yaitu:

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

Penjelasan:

Secara default, jika Anda ingin mengarahkan permintaan dengan data POST, browser mengalihkannya melalui GET dengan 302 redirect. Ini juga menjatuhkan semua data POST yang terkait dengan permintaan . Browser melakukan ini sebagai tindakan pencegahan untuk mencegah pengiriman ulang transaksi POST yang tidak disengaja.

Tetapi bagaimana jika Anda tetap ingin mengarahkan permintaan POST dengan datanya? Di HTTP 1.1, ada kode status untuk ini. Kode status 307menunjukkan bahwa permintaan harus diulangi dengan metode dan data HTTP yang sama. Jadi permintaan POST Anda akan diulang bersama dengan datanya jika Anda menggunakan kode status ini.

SRC

HUBUNGI19
sumber
2

Saya menghadapi masalah serupa dengan Permintaan POST di mana Permintaan GET bekerja dengan baik pada backend saya yang saya lewati variabel saya dll. Masalahnya terletak di sana bahwa backend melakukan banyak pengalihan, yang tidak bekerja dengan metode fopen atau header php.

Jadi satu-satunya cara saya membuatnya bekerja adalah dengan meletakkan formulir tersembunyi dan mendorong nilai-nilai dengan mengirimkan POST ketika halaman dimuat.

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

Anda dapat menggunakan sesi untuk menyimpan $_POSTdata, lalu mengambil data itu dan mengaturnya $_POSTsesuai permintaan berikutnya.

Pengguna mengirimkan permintaan ke /dirty-submission-url.php
Do:

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

Kemudian browser mengalihkan ke dan permintaan /clean-submission-urldari server Anda. Anda akan memiliki beberapa perutean internal untuk mencari tahu apa yang harus dilakukan dengan ini.
Di awal permintaan, Anda akan melakukan:

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

Sekarang, melalui sisa permintaan Anda, Anda dapat mengakses $_POSTsebanyak yang Anda bisa atas permintaan pertama.

Reed
sumber
Anda dapat memproses $_POSTdata sebagai string kueri dan meneruskannya ke halaman berikutnya dengan cara itu. Tapi kemudian datanya tidak bisa terlalu besar. Dan ini mungkin tidak berfungsi jika unggahan file terlibat, tapi saya tidak yakin.
Reed
0

Coba ini:

Kirim data dan permintaan dengan header http di halaman B untuk mengarahkan ulang ke Gateway

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

Tajuk Tambahan:

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
pengguna3754884
sumber
0

Di sini ada pendekatan lain yang berfungsi untuk saya:

jika Anda perlu mengarahkan ulang ke halaman web lain ( user.php) dan menyertakan variabel PHP ( $user[0]):

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

atau

header("Location:./user.php?u_id=$user[0]");
Lucho
sumber
Alternatif tersebut dimaksudkan untuk menggunakan protokol GET. Itu memperlihatkan variabel pada browser klien. OP menginginkan perilaku yang sama dengan 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();
}

Contoh:

 post('url', {name: 'Johnny Bravo'});
njoshsn
sumber