Redirection PHP avec données POST


241

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

Ma situation:

Page A: [checkout.php] Le client remplit ses informations de facturation.

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

Page C: [thirdparty.com] Troisième passerelle de paiement (ACCEPTER UNIQUEMENT LES DONNÉES DE POST).

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

La passerelle de paiement tiers nous a donné l'échantillon API, l'échantillon est POST le numéro de facture avec les détails du client. Nous ne voulons pas que le système génère un excès de numéros de factures indésirables.

Existe-t-il une solution à ça? Notre solution actuelle est que le client remplisse les détails dans la page A, puis dans la page B, nous créons une autre page affichant tous les détails du client là-bas, où l'utilisateur peut cliquer sur un bouton CONFIRMER pour POSTER sur la page C.

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

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


Je ne pense pas que c'est en double pour cela, c'est parce que mon objectif est à l'intérieur d'une page PHP, passer les données POST et les rediriger. cURL Je ne pense pas qu'il soit possible de le faire. Il suffit de chercher un expert pour toute alternative
Shiro

ʜᴛᴛᴘ 308 code de redirection?
user2284570

Réponses:


212

Générez un formulaire sur la page B avec toutes les données et actions requises définies sur la page C et soumettez-le avec JavaScript au 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 URI différent et DEVRAIT être récupérée à l'aide d'une méthode GET sur cette ressource. Cette méthode existe principalement pour permettre à la sortie d'un script activé par 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 initialement demandée. La réponse 303 NE DOIT PAS être mise en cache, mais la réponse à la deuxième demande (redirigée) peut être mise en cache.

La seule façon d'atteindre ce que vous faites est d'utiliser une page intermédiaire qui envoie l'utilisateur à la page 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>

Vous devriez également avoir un simple formulaire de «confirmation» à l'intérieur d'une balise noscript pour vous assurer que les utilisateurs sans Javascript pourront utiliser votre service.


2
mon objectif est dans la page A -> la page C, la page B est le contrôleur (logique métier) générer le numéro de facture. De la vue système se trouve la page A-> la page B-> la page C, mais de la vue utilisateur doit être la page A-> la page B, ils ne doivent jamais libérer la page B existante.
Shiro

3
@Peeter: suggestion intelligente +1. Le seul problème est que lorsque l'utilisateur sur le bouton-poussoir de la page C est renvoyé à la page C. De plus, vous avez oublié de coder le $aet $ben utilisant htmlentities/htmlspecialchars, voir stackoverflow.com/questions/6180072/php-forward-data-post/…
Marco Demaio

8
question ici, que faire si Javascript est désactivé sur le client? La page B ne redirigera pas vers la page C, n'est-ce pas?
Imran Omar Bukhsh,

24
<noscript><input type="submit" value="Click here if you are not redirected."/></noscript>à l'intérieur de<form>
nullité

3
l' languageattribut est obsolète, il devrait l'être<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
Bien qu'au début, cela semble également mieux que la réponse acceptée, je note qu'elle ne redirige pas vers la $urlréponse fournie - Elle remplace simplement le contenu de la page existante par le contenu de la $urlpage. Surtout , le code php dans la $urlpage n'est pas évalué.
iPadDeveloper2011

@ iPadDeveloper2011, dans l'URL, vous n'avez pas de code PHP! Le code PHP est exécuté dans le SERVEUR, pas dans le client.
Eduardo Cuomo

1
redirect_post(), qui est côté serveur, le code php, envoie une requête au SERVEUR pour a $url. Si $urlc'est une .phppage, je note que le php n'est pas évalué - le html est retourné avec des balises php toujours dedans. N'est-il pas utile d'envoyer des données POST à ​​un script côté serveur?
iPadDeveloper2011

2
@EduardoCuomo cette méthode ne fonctionne qu'avec des URL absoulte, à cause du fonctionnement de fopen (): php.net/manual/en/function.fopen.php C'est toujours une réponse assez astucieuse.
Omn

@Omn tu as raison! "Cela ne fonctionne pas avec une URL relative?" n'est pas une question, c'est une déclaration. Désolé pour la confusion
Eduardo Cuomo

25

J'ai une autre solution qui rend cela possible. Cela nécessite que le client exécute Javascript (ce qui, je pense, est une exigence équitable de nos jours).

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

Vous obtiendrez ainsi votre résultat en cliquant sur un seul bouton et en passant à la passerelle de paiement. Voici un pseudocode

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 (en utilisant jQuery pour plus de commodité mais trivial pour faire 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
  }
});

1
Cette solution a un problème, si quelqu'un désactive le JavaScript dans cette page, actualise et soumet, il ira à la page de paiement sans rien enregistrer. cela pourrait être une faille.
caoglish

2
Ensuite, ne définissez l'action paymentForm qu'avec Javascript? Si JS est désactivé, le formulaire ne sera pas envoyé.
MikeMurko

L'utilisateur désactivant JS ne devrait pas nous poser de problème - la raison pour laquelle nous devons aller à la page B est probablement pour générer une empreinte digitale ou ajouter un code de commande, etc. Sans cela, la page tierce C devrait échouer, ou au pire, lorsque le résultat nous revient du tiers sans code de commande, nous ne devons pas accepter la commande. C'est globalement une bonne solution si JS est acceptable.
Coder

19

$ _SESSION est votre ami si vous ne voulez pas jouer avec Javascript

Supposons que vous essayez de transmettre un e-mail:

À la page A:

// Start the session
session_start();

// Set session variables
$_SESSION["email"] = "awesome@email.com";

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

Pour détruire la session

unset($_SESSION['email']);
session_destroy();

pourquoi considérez-vous cela comme moins sûr que la version javascript?
Adam Baranyai

1
non, je veux dire pas comparé à javascript. Juste en général, $ _SESSION seul peut être un peu moins sécurisé que disons $ _SESSION + cookie, bien que $ _SESSION soit assez sécurisé en lui-même. Plus d'infos ici: stackoverflow.com/questions/17413480/session-spoofing-php
Robert Sinclair

et comment fermer la session?
Sayed Muhammad Idrees

Avez-vous besoin de fermer la session?
Ivan P.

6

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

Donc, en quelque sorte ce que vous avez suggéré, vous obtiendrez en effet cette partie:

Détails de remplissage du client dans la page A, puis dans la page B, nous créons une autre page pour afficher tous les détails du client, cliquez sur un bouton CONFIRMER, puis POSTEZ sur la page C.

Mais vous pouvez réellement faire une soumission javascript sur la page B, donc il n'est pas nécessaire de cliquer. Faites-en une page de "redirection" avec une animation de chargement, et vous êtes prêt.


C'est ce que nous faisons maintenant. Je pense qu'il existe une meilleure logique PHP pour le résoudre. Merci. ;)
Shiro

ya, plus vers HTTP, mais je travaille en environnement PHP, donc je pense que c'est à la fois tag. Merci! Col Shrapnel.
Shiro

6

Je sais que c'est une vieille question, mais j'ai encore une autre solution alternative avec 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();

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

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


5

Il y a un simple hack, utilisez $_SESSIONet créez une arraydes valeurs publiées, et une fois que vous allez sur le site, File_C.phpvous pouvez l'utiliser, puis le traitez-vous après l'avoir détruit.


pouvez-vous donner un petit exemple de ce que vous voulez dire?
caro

3
Ma compréhension est, la page C est une source externe, qui prend des valeurs de publication mais pas de sessions.
Narayan Bhandari

3

Je suis conscient que la question est phporientée, mais la meilleure façon de rediriger unPOST demande 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 des données POST, le navigateur la redirige via GET avec 302 redirect . Cela supprime également toutes les données POST associées à la demande . Le navigateur le fait par précaution pour empêcher toute nouvelle soumission involontaire de la transaction POST.

Mais que se passe-t-il si vous souhaitez rediriger de toute façon la demande POST avec ses données? Dans HTTP 1.1, il existe un code d'état pour cela.Le code d'état 307indique 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


2

J'ai rencontré des problèmes similaires avec POST Request où GET Request fonctionnait bien sur mon backend, je transmets mes variables, etc. Le problème réside dans le fait que le backend fait beaucoup de redirections, ce qui ne fonctionnait pas avec fopen ou les méthodes d'en-tête php.

Donc, la seule façon de le faire fonctionner était de mettre un formulaire caché et de pousser les valeurs avec une soumission POST lorsque la page est chargée.

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

Vous pouvez utiliser des sessions pour enregistrer des $_POSTdonnées, puis récupérer ces données et les définir $_POSTsur la demande suivante.

Soumet l' utilisateur demande à /dirty-submission-url.php
Do:

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

Ensuite, le navigateur redirige et demande /clean-submission-urlà 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']);
}

Maintenant, pendant le reste de votre demande, vous pouvez accéder $_POSTcomme vous le pouviez à la première demande.


Vous pouvez également traiter les $_POSTdonnées dans une chaîne de requête et les transmettre à la page suivante de cette façon. Mais alors les données ne peuvent pas être trop terriblement volumineuses. Et cela ne fonctionne probablement pas si des téléchargements de fichiers sont impliqués, mais je ne suis pas sûr.
Reed

0

Essaye ça:

Envoyer des données et demander avec l'en-tête http dans la page B pour 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

Voici une autre approche qui fonctionne pour moi:

si vous devez rediriger vers une autre page Web ( user.php) et inclut une variable PHP ( $user[0]):

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

ou

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

Ces alternatives sont destinées à utiliser le protocole GET. Il expose des variables sur le navigateur du client. OP voulait plutôt le même comportement avec 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();
}

Exemple:

 post('url', {name: 'Johnny Bravo'});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.