PHP Redirect с данными POST


241

Я провел некоторое исследование по этой теме, и есть некоторые эксперты, которые сказали, что это невозможно , поэтому я хотел бы попросить альтернативное решение.

Моя ситуация:

Страница A: [checkout.php] Клиент заполняет свои платежные реквизиты.

Страница B: [process.php] Создайте номер счета и сохраните информацию о клиенте в базе данных.

Страница C: [thirdparty.com] Третий платежный шлюз (ТОЛЬКО ПРИНИМАЮТ ПОЧТОВЫЕ ДАННЫЕ).

Клиент заполняет свои данные и устанавливает свою корзину на странице A, затем отправляет POST на страницу B. Внутри process.php сохраняют данные POST в базе данных и генерируют номер счета-фактуры. После этого отправьте данные клиента и номер счета на платежный шлюз Thirdparty.com. Проблема заключается в выполнении процедуры POST на странице B. cURL может отправить данные на страницу C, но проблема заключается в том, что страница не перенаправлена ​​на страницу C. Клиент должен заполнить данные кредитной карты на странице C.

Сторонний платежный шлюз предоставил нам пример API, образец POST - номер счета-фактуры вместе с данными клиента. Мы не хотим, чтобы система генерировала избыток нежелательных номеров счетов.

Есть ли решение для этого? Наше текущее решение заключается в том, чтобы клиент заполнял детали на странице A, а затем на странице B мы создаем еще одну страницу, на которой отображаются все данные клиента, где пользователь может нажать кнопку ПОДТВЕРДИТЬ, чтобы отправить сообщение на страницу C.

Наша цель - чтобы клиенты нажимали только один раз.

Надеюсь, мой вопрос ясен :)


я не думаю, что это дублирует это, потому что моя цель - попасть на страницу PHP, передать данные POST и перенаправить их. CURL Я не думаю, что это возможно сделать. Просто ищите эксперта любую альтернативу для этого
Широ

ʜᴛᴛᴘ 308 код перенаправления?
user2284570

Ответы:


212

Создайте форму на странице B со всеми необходимыми данными и действиями, установленными на странице C, и отправьте ее с JavaScript при загрузке страницы. Ваши данные будут отправлены на страницу C без особых хлопот для пользователя.

Это единственный способ сделать это. Перенаправление - это HTTP-заголовок 303, который вы можете прочитать на http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html , но я приведу некоторые из них:

Ответ на запрос может быть найден под другим 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, чтобы пользователи без Javascript могли использовать ваш сервис.


2
моя цель на странице A -> страница C, страница B - это контроллер (бизнес-логика), генерирующий номер счета. С системной точки зрения это страница A-> страница B-> страница C, но с точки зрения пользователя должна быть страница A-> страница B, они никогда не должны выпускать страницу B.
Широ

3
@Peeter: умное предложение +1. Единственная проблема в том , что , когда пользователь на кнопку оттеснить Page C повторно передается странице C. Кроме того , вы забыли кодировать $aи $bс помощью htmlentities/htmlspecialchars, см stackoverflow.com/questions/6180072/php-forward-data-post/...
Marco DeMaio

8
Вопрос здесь в том, что, если Javascript отключен на клиенте? Страница B не будет перенаправлять на страницу C, не так ли?
Имран Омар Бухш

24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>внутри<form>
обнуляемость

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страницы. Важно отметить , что PHP-код на $urlстранице не оценивается.
iPadDeveloper2011

@ iPadDeveloper2011, в URL у вас нет кода PHP! Код PHP выполняется в СЕРВЕРЕ, а не в клиенте.
Эдуардо Куомо

1
redirect_post(), который на стороне сервера, php code, отправляет запрос на СЕРВЕР для $url. Если $urlэто .phpстраница, я отмечаю, что php не оценивается - возвращается html с тегами php. Разве нет смысла отправлять POST-данные в сценарий на стороне сервера?
iPadDeveloper2011

2
@EduardoCuomo, этот метод работает только с абсолютными URL-адресами из-за того, как работает fopen (): php.net/manual/en/function.fopen.php. Это все еще довольно изящный ответ.
Omn

@ Ты прав! "Это не работает с относительным URL?" это не вопрос, это утверждение. Извините за путаницу
Эдуардо Куомо

25

У меня есть другое решение, которое делает это возможным. Это требует, чтобы клиент работал под управлением Javascript (что я считаю справедливым требованием в наши дни).

Просто используйте AJAX-запрос на странице A, чтобы перейти и сгенерировать номер счета-фактуры и данные клиента в фоновом режиме (ваша предыдущая страница 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 на этой странице, обновит его и отправит, он перейдет на страницу оплаты без сохранения чего-либо. это может быть лазейка
caoglish

2
Тогда только установить действие paymentForm с Javascript? Если JS отключен, форма не будет отправлена.
MikeMurko

Пользователь, отключающий JS, не должен вызывать у нас проблемы - причина, по которой мы должны перейти на страницу B, вероятно, состоит в том, чтобы сгенерировать отпечаток пальца или добавить код заказа и т. Д. Без этого сторонняя страница C может выйти из строя или, в худшем случае, когда результат возвращается к нам от третьей стороны без кода заказа, мы не должны принимать заказ. В целом это хорошее решение, если JS приемлемо.
Кодер

19

$ _SESSION - ваш друг, если вы не хотите связываться с Javascript

Допустим, вы пытаетесь передать письмо:

На странице А:

// 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?
Адам Бараньяй

1
нет, я имею в виду не по сравнению с javascript. В общем, только $ _SESSION может быть немного менее безопасным, чем, скажем, $ _SESSION + cookie, хотя $ _SESSION сам по себе довольно безопасен. Более подробная информация здесь: stackoverflow.com/questions/17413480/session-spoofing-php
Роберт Синклер,

а как закрыть сессию?
сказал Мухаммед Идриес

Вам нужно закрыть сессию?
Иван П.

6

Вы можете позволить PHP делать POST, но тогда ваш php получит ответ, со всеми видами сложностей. Я думаю, что самым простым было бы на самом деле позволить пользователю делать POST.

Итак, вроде того, что вы предложили, вы действительно получите эту часть:

Сведения о клиенте заполняются на странице A, затем на странице B мы создаем еще одну страницу, на которой отображаются все сведения о клиенте, нажмите кнопку ПОДТВЕРДИТЬ, затем POST на страницу C.

Но на самом деле вы можете сделать отправку javascript на странице B, поэтому нет необходимости в клике. Сделайте «страницу перенаправления» с анимацией загрузки, и все готово.


Это то, что мы делаем сейчас. Я думаю, есть ли в 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.

ps JavaScript и jQuery требуются для этого случая. Как следует из комментариев других ответов, вы можете использовать <noscript>тег для создания стандартной формы HTML в случае, если JS отключен.


5

Существует простой способ взлома, использования $_SESSIONи создания arrayобъявленных значений, и как только вы перейдете к нему, File_C.phpвы сможете использовать его, а затем обработать, после чего уничтожить его.


Можете ли вы привести небольшой пример того, что вы имеете в виду?
Каро

3
Насколько я понимаю, страница C является внешним источником, который принимает значения записей, но не сеансы.
Нараян Бхандари

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

Таким образом, единственный способ, с помощью которого я работал, состоял в том, чтобы поместить скрытую форму и передать значения с помощью отправки 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

Попробуй это:

Отправьте данные и запрос с заголовком http на странице B для перенаправления на шлюз

<?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 вместо этого.
Серхио А.

-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'});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.