第三方支付回调后PHP Session变量丢失问题求助
第三方支付回调后PHP Session丢失问题解决
问题说明

以下是第三方支付的回调响应处理代码,当前遇到的问题是:获取支付回调响应后,PHP Session变量被销毁,出现截图中的警告错误。已在发起支付网关请求前设置好PHP Session变量。
回调处理代码
session_start(); $servername = "localhost"; $username = "root"; $dbname = "srdb"; $password = ""; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } if( isset($_SERVER['HTTPS'] ) ) { $host ='https'; }else{ $host = 'http'; } require_once 'TransactionResponseBean.php'; $parameters = file_get_contents("./parameters.json"); $data = json_decode($parameters, true); $protocolType = 'http'; if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { $protocolType = 'https'; } if(!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '80'){ $hostStr = "$protocolType://$_SERVER[SERVER_NAME]$_SERVER[SCRIPT_NAME]"; }else{ $hostStr = "$protocolType://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]$_SERVER[SCRIPT_NAME]"; } $resHost = explode('/', $hostStr); array_pop($resHost); $resHost = implode('/', $resHost); ?> <html> <head> <title>Payment Response</title> <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1" / > <link rel="stylesheet" href="<?php echo $resHost . '/assets/css/bootstrap.min.css';?>"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" type="text/javascript"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-print-css/css/bootstrap-print.min.css" media="print"> <script src="<?php echo $resHost . '/assets/js/bootstrap.min.js';?>"></script> <script src="js/response.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <?php include 'logotext.php';?> <div class="container"> <?php include 'userdisplay.php';?> <?php include 'nav.php';?> </div> <?php if ($_POST) { if (isset($_POST['msg'])) { $response = $_POST; if (is_array($response)) { $str = $response['msg']; } else if (is_string($response) && strstr($response, 'msg=')) { $outputstr = str_replace('msg=', '', $response); $outputArr = explode('&', $outputstr); $str = $outputArr[0]; } else { $str = $response; } $transactionResponseBean = new TransactionResponseBean(); $transactionResponseBean->setResponsePayload($str); $transactionResponseBean->key = $data['key']; $transactionResponseBean->iv = $data['iv']; $response = $transactionResponseBean->getResponsePayload(); //Writing in Response Log $log = "Date : ".date("F j, Y, g:i a")."; Response Data : ".$response.PHP_EOL; //Saving string to log by using "FILE_APPEND" to append. file_put_contents('logs/response/log_'.date("j.n.Y").'.log', $log, FILE_APPEND); $response_n = explode("|", $response); //print_r($response_n); display_response($response_n,$data); } else if (isset($_POST['response'])) { //Writing in Response Log $log = "Date : ".date("F j, Y, g:i a")."; Response Data : ".$_POST['response'].PHP_EOL; //Saving string to log by using "FILE_APPEND" to append. file_put_contents('logs/response/log_'.date("j.n.Y").'.log', $log, FILE_APPEND); $response_n = explode("|", $_POST['response']); display_response($response_n,$data); } } else { echo "No Response Received"; } ?> </body> </html> <?php function display_response($res, $parameters) { $payment_array = array(); $stat = $res[0]; $mystatus = explode("=", $stat); $status = $mystatus[1]; $message; echo '<div class="container" id="print-div"> <div class="row"> <div class="col-md-12"> <form action="response_handler.php" method="POST"> <table class="table table-bordered table-hover"> <tr class="info"> <th width="100%" style="text-align:center" colspan="2">Transaction Acknowledgement</th> </tr> <tr> <td>Applicant Name</td><td>'.$_SESSION['appname'].'</td> </tr> <tr> <td>Applicant ID</td><td>'.$_SESSION['appid'].'</td> </tr>'; foreach ($res as $val) { $response1 = explode("=", $val); array_push($payment_array,$response1[1]); if( $response1[0] == 'txn_err_msg' && $status == '0300'){ continue; } $data = getdetails($response1[0], $parameters); if (!(empty($data))) { $colum_name = $data; } else { continue; } if (empty($response1[1])) { $response1[1] = "Not found"; } echo "<tr>"; echo "<td> $colum_name </td>"; if($response1[1] == "0300" || $response1[1] == "success"){ $message="success"; echo "<td style='background-color: darkseagreen;color: aliceblue;'> $response1[1] </td>"; }elseif ($response1[1] == "0399" || $response1[1] == "failure") { $message="failure"; echo "<td style='background-color: red;color: white;'> $response1[1] </td>"; }else{ echo "<td> $response1[1] </td>"; } echo "</tr>"; } echo "</table> </div> </div> </div>"; $sql_load_payment = "INSERT INTO payment_details VALUES('$session_appid','$payment_array[0]','$payment_array[1]','$payment_array[2]','$payment_array[3]','$payment_array[6]','$payment_array[8]','$payment_array[5]')"; $conn->query($sql_load_payment); if($message === "success"){ $sql_stat = "UPDATE final_status SET payment='DONE' WHERE app_id='$session_appid'"; $conn->query($sql_stat); } $conn->close(); echo '<div class="container"> <div class="row"> <div class="col-md-12">'; echo "<input type='button' name='print' value='save' id='save'/>"; if($message == 'success'){ echo "<input type='submit' name='pbtn' value='Proceed'/>"; } if($message == 'failure'){ echo "<input type='submit' name='rbtn' value='Retry Payment'/>"; } echo '</form> </div> </div> </div>'; } function getdetails($code, $parameters) { if($parameters['showAllResponse'] == "ON"){ $column_value = [ "txn_status" => "Transaction Status", "txn_msg" => "Message", "txn_err_msg" => "Error Message", "clnt_txn_ref" => "Transaction ID", "tpsl_bank_cd" => "TPSL Bank Code", "tpsl_txn_id" => "TPSL Transaction ID", "txn_amt" => "Amount", "tpsl_txn_time" => "Transaction Time", "tpsl_rfnd_id" => "TPSL Refund ID", "bal_amt" => "Balance Amount", "REFUND_DETAILS" => "Refund details", "rqst_token" => "Request Token", "bank_name" => "Bank Name", "card_id" => "Card ID", "alias_name" => "Alias Name", "card_Type" => "Card Type", "Card_Expiry" => "Card Expiry", "hash" => "Hash", "BANK_TYPE" => "Bank Type", "auth" => "Auth" ]; } else{ $column_value = [ "txn_status" => "Transaction Status", "txn_msg" => "Message", "txn_err_msg" => "Error Message", "clnt_txn_ref" => "Transaction ID", "tpsl_bank_cd" => "TPSL Bank Code", "tpsl_txn_id" => "TPSL Transaction ID", "txn_amt" => "Amount", "REFUND_DETAILS" => "Refund details", "bank_name" => "Bank Name" ]; } if (in_array($code, array_keys($column_value))) { return $column_value[$code]; } } ?>
解决方案
1. 确保Session初始化无输出干扰
把session_start();放在PHP脚本的最开头,确保它在任何HTML输出、空格甚至UTF-8 BOM字符之前执行。隐性输出会破坏Session的初始化流程,修改后开头应为:
<?php session_start(); // 后续代码...
2. 解决第三方回调的Session隔离问题
支付网关的回调是服务器端发起的请求,不会携带用户浏览器的Session Cookie,因此当前用户的Session无法直接复用。解决办法:
- 发起支付时,将用户的
session_id()或关键标识(比如$_SESSION['appid'])作为自定义参数传递给支付网关(具体参考支付网关文档,多数支持传递自定义回调参数)。 - 回调时,从POST参数中获取该标识:
- 如果是Session ID,执行
session_id($received_session_id);后再调用session_start();恢复Session。 - 如果是appid,直接从数据库查询用户信息,替代Session变量的使用(更安全可靠)。
- 如果是Session ID,执行
3. 修复代码中的变量错误
display_response函数中使用了未定义的$session_appid,替换为$_SESSION['appid'](或从回调参数中获取的appid)。$conn变量在函数内未定义,由于函数有独立作用域,需将$conn作为参数传入函数,或在函数内重新初始化数据库连接(推荐传参)。修改后的函数定义及调用示例:
// 修改函数定义 function display_response($res, $parameters, $conn, $appid) { // 用$appid替代原$session_appid $sql_load_payment = "INSERT INTO payment_details VALUES('$appid','$payment_array[0]','$payment_array[1]','$payment_array[2]','$payment_array[3]','$payment_array[6]','$payment_array[8]','$payment_array[5]')"; $conn->query($sql_load_payment); // 后续代码... } // 调用时传入参数 display_response($response_n,$data, $conn, $_SESSION['appid']);
4. 检查Session配置
查看php.ini中的相关配置项:
session.cookie_domain:设置为当前域名,避免Cookie跨域无法传递。session.cookie_secure:若网站使用HTTPS,设置为On,确保Cookie仅通过HTTPS传输。session.cookie_lifetime:设置合理的有效期,避免Session过早过期。
内容的提问来源于stack exchange,提问作者kapil joshi
相关产品推荐
相关产品推荐

