web-dev-qa-db-fra.com

PHP Redirection avec POST data

J'ai fait des recherches sur ce sujet, et certains experts ont dit que ce n'était pas possible , alors j'aimerais demander une solution alternative.

Ma situation:

Page A: [checkout.php] Le client renseigne ses détails de facturation.

Page B: [process.php] Générez un numéro de facture et enregistrez les détails du client dans la base de données.

Page C: [thirdparty.com] Troisième passerelle de paiement (UNIQUEMENT ACCEPTER POST DATA).

Le client renseigne ses coordonnées et configure son panier dans la page A, puis en POST sur la page B. Dans process.php, stocke les données POST dans la base de données et génère un numéro de facture. Après cela, POST _ les données client et le numéro de facture à la passerelle de paiement thirdparty.com. Le problème concerne POST à la page B. cURL est capable de POST les données de la page C, mais le problème est que la page n'a pas été redirigée vers la page C. Le client doit remplissez les détails de votre carte de crédit à la page C.

La passerelle de paiement tierce nous a fourni l’échantillon d’API. L’échantillon est POST le numéro de facture et les coordonnées du client. Nous ne voulons pas que le système génère trop de factures non désirées.

Existe-t-il une solution à ça? Notre solution actuelle consiste pour le client à remplir les détails dans la page A, puis dans la page B, nous créons une autre page contenant tous les détails du client. L'utilisateur peut cliquer sur un bouton CONFIRMER pour POST vers la page C.

Notre objectif est que les clients n’aient à cliquer qu’une fois.

J'espère que ma question est claire :)

214
Shiro

Générez un formulaire sur la page B avec toutes les données requises et l'action définie sur la page C et soumettez-le avec JavaScript lors du chargement de la page. Vos données seront envoyées à la page C sans trop de soucis pour l'utilisateur.

C'est la seule façon de le faire. Une redirection est un en-tête HTTP 303 que vous pouvez lire sur http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html , mais je vais en citer une partie:

La réponse à la demande peut être trouvée sous un autre URI et DEVRAIT être extraite à l'aide d'une méthode GET sur cette ressource. Cette méthode existe principalement pour permettre à la sortie d'un script activé par le POST de rediriger l'agent utilisateur vers une ressource sélectionnée. Le nouvel URI n'est pas une référence de remplacement pour la ressource demandée à l'origine. La réponse 303 NE DOIT PAS être mise en cache, mais la réponse à la seconde demande (redirigée) peut être mise en cache.

Le seul moyen d'obtenir ce que vous faites est d'utiliser une page intermédiaire qui envoie l'utilisateur à la page C. Voici un extrait de code simple/simple expliquant comment y parvenir:

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

Vous devez également avoir un simple formulaire de confirmation dans une balise noscript pour vous assurer que les utilisateurs sans Javascript pourront utiliser votre service.

192
Peeter
/**
 * 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");
    }
}
32
Eduardo Cuomo

J'ai une autre solution qui rend cela possible. Il faut que le client utilise Javascript (ce qui, à mon avis, est une exigence juste de nos jours).

Utilisez simplement une demande AJAX sur la page A pour générer le numéro de votre facture et les détails de votre client en arrière-plan (votre précédente page B), puis une fois que la demande est renvoyée avec les informations correctes, remplissez simplement le formulaire. la soumission à votre passerelle de paiement (page C).

Vous obtiendrez ainsi le résultat suivant: l'utilisateur ne clique que sur un bouton et passe à la passerelle de paiement. Ci-dessous quelques pseudocodes

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 (utiliser jQuery pour des raisons pratiques mais trivial pour créer du Javascript pur):

$('#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
  }
});
22
MikeMurko

$ _SESSION est votre ami si vous ne voulez pas vous mêler de Javascript et que cela ne vous dérange pas d'être un peu moins sécurisé.

Disons que vous essayez de passer un email:

Sur la page A:

// Start the session
session_start();

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

header('Location: page_b.php');

Et à la page B:

// Start the session
session_start();

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

Vous pouvez laisser PHP faire un post, mais votre php aura le retour, avec toutes sortes de complications. Je pense que le plus simple serait de laisser l’utilisateur effectuer le POST.

Donc, genre de ce que vous avez suggéré, vous obtiendrez en effet cette partie:

Le client remplit les détails dans la page A, puis dans la page B, nous créons une autre page qui affiche tous les détails du client. Cliquez sur un bouton CONFIRMER, puis sur POST sur la page C.

Mais vous pouvez réellement effectuer une soumission javascript sur la page B, vous n’avez donc pas besoin d’un clic. Faites-en une page de "redirection" avec une animation de chargement, et le tour est joué.

6
Nanne

Je sais que c’est une vieille question, mais jQuery a une autre solution alternative:

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

Le code ci-dessus utilise jQuery pour créer une balise de formulaire, en ajoutant des champs cachés en tant que champs de publication et en dernier lieu. La page sera transmise à la page cible du formulaire avec les données POST jointes.

p.s. JavaScript et jQuery sont requis pour ce cas. Comme suggéré par les commentaires des autres réponses, vous pouvez utiliser la balise <noscript> pour créer un formulaire HTML standard au cas où JS serait désactivé.

6
Raptor

Il y a un hack simple, utilisez $_SESSION et créez un array des valeurs postées, et une fois que vous accédez au File_C.php, vous pouvez l'utiliser, puis le traiter après sa destruction.

5
Jeffery ThaGintoki

Vous pouvez utiliser des sessions pour enregistrer les données $_POST, puis les récupérer et les définir sur $_POST lors de la requête suivante.

L'utilisateur soumet une demande à /dirty-submission-url.php
Faire:

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

Ensuite, le navigateur redirige vers et demande /clean-submission-url de votre serveur. Vous aurez un routage interne pour savoir quoi faire avec cela.
Au début de la demande, vous ferez:

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

Désormais, vous pouvez accéder à $_POST comme vous le pouviez lors de la première demande.

1
Reed

Je suis conscient que la question est orientée php, mais le meilleur moyen de rediriger une demande POST est probablement d'utiliser .htaccess, c'est-à-dire:

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

Explication:

Par défaut, si vous souhaitez rediriger la demande avec POST data, le navigateur la redirige via GET avec 302 redirect. Cela supprime également toutes les POST données associées à la demande . Le navigateur effectue cette opération par précaution pour empêcher toute nouvelle soumission involontaire de la transaction POST.

Mais que faire si vous voulez quand même rediriger POST demander avec ses données? Dans HTTP 1.1, il existe un code d'état pour cela. Le code d'état 307 indique que la demande doit être répétée avec la même méthode HTTP et les mêmes données. Ainsi, votre demande POST sera répétée avec ses données si vous utilisez ce code d'état.

SRC

0
Pedro Lobito

Essaye ça:

Envoyer des données et demander avec l'en-tête http de la page B de rediriger vers la passerelle

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

En-têtes supplémentaires:

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
user3754884