【问题标题】:PayPal IPN and fsockopenPayPal IPN 和 fsockopen
【发布时间】:2016-04-29 18:04:24
【问题描述】:

我不能使用 cURL,安装在我的 web 主机上的无法更改的版本不支持 TLS。

我现在正在尝试使用 fsockopen 看看是否可以使用 IPN。

它只是挂起,浏览器抛出连接超时。

PHP 7,open_ssl 已启用

<?php
    header('HTTP/1.1 200 OK'); 

    $item_name        = $_POST['item_name'];
    $item_number      = $_POST['item_number'];
    $payment_status   = $_POST['payment_status'];
    $payment_amount   = $_POST['mc_gross'];
    $payment_currency = $_POST['mc_currency'];
    $txn_id           = $_POST['txn_id'];
    $receiver_email   = $_POST['receiver_email'];
    $payer_email      = $_POST['payer_email'];

    $req = 'cmd=_notify-validate';               // Add 'cmd=_notify-validate' to beginning of the acknowledgement
    foreach ($_POST as $key => $value) {         // Loop through the notification NV pairs
        $value = urlencode(stripslashes($value));  // Encode these values
        $req  .= "&$key=$value";                   // Add the NV pairs to the acknowledgement
    }

    // Set up the acknowledgement request headers
    $header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";                    // HTTP POST request
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

    // Open a socket for the acknowledgement request
     $fp = fsockopen('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

    // Send the HTTP POST request back to PayPal for validation
    fputs($fp, $header . $req);

    while (!feof($fp)) {                     // While not EOF

    $res = trim(fgets ($fp, 1024));

    if (strcmp ($res, "VERIFIED") == 0) {  // Response contains VERIFIED - process notification

      file_put_contents('./log_'.date("j.n.Y").'.txt', 'VERIFIED', FILE_APPEND);
    } 
    else if (strcmp ($res, "INVALID") == 0) { Response contains INVALID - reject notification
        file_put_contents('./log_'.date("j.n.Y").'.txt', 'INVALID', FILE_APPEND);
    }
  }
  //close
  fclose($fp);
?>

更新

所以这似乎是我当前代码的问题。我使用以下内容查看是否可以与 PayPal 通话。

<?php

$site = "sandbox.paypal.com";//works
$port = 443;

$fp = fsockopen($site, $port, $errno, $errstr, 30);

if(!$fp){
  echo "<b>The port is NOT open!</b>";
}else{
  echo "<b>The port is open!</b>";
  fclose($fp);
}

?>

结果是The port is open!

更新 2

好的,我现在使用以下代码从 IPN 模拟器获得响应。我遇到的其他问题是我未能使用我的听众的 FQDN 并离开了 http://。

所以现在下一个问题是$res = trim($res); 总是空白,但我的帖子变量不是。这是因为它是沙盒吗?

<?php 
    $debug            = 1;
    $sandbox          = 1;

    header('HTTP/1.1 200 OK'); 

    $item_name        = $_POST['item_name'];
    $item_number      = $_POST['item_number'];
    $payment_status   = $_POST['payment_status'];   
    if ($_POST['mc_gross'] != null) {
        $payment_amount   = $_POST['mc_gross'];
    } else {
        $payment_amount   = $_POST['mc_gross1'];
    }
    $payment_currency = $_POST['mc_currency'];
    $txn_id           = $_POST['txn_id'];
    $receiver_email   = $_POST['receiver_email'];
    $payer_email      = $_POST['payer_email'];
    $payment_date     = $_POST['payment_date'];
    $first_name       = $_POST['first_name'];
    $last_name        = $_POST['last_name'];
    $item_name        = $_POST['item_name'];

    $sandbox_url      = "sandbox.paypal.com";
    $prod_url         = "paypal.com";
    $verfiy_email     = "you email address the payment should be made to";

    if ($sandbox) {
        $url = $sandbox_url;
    } else {
        $url = $prod_url;
    }

    if ($debug) {
        error_log(date('[Y-m-d H:i e] '). "IPN URL: " . $url . PHP_EOL, 3, LOG_FILE);
    }

    $req = 'cmd=_notify-validate';               // Add 'cmd=_notify-validate' to beginning of the acknowledgement
    foreach ($_POST as $key => $value) {         // Loop through the notification NV pairs
        $value = urlencode(stripslashes($value));  // Encode these values
        $req  .= "&$key=$value";                   // Add the NV pairs to the acknowledgement

        if ($debug) {
            error_log(date('[Y-m-d H:i e] '). "POST Data: " . $key . " - " . $value . PHP_EOL, 3, LOG_FILE);
        }
    }

    //post back to PayPal system to validate (replaces old headers)
    $header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Host: www." . $url . "\r\n";
    $header .= "Connection: close\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
    $fp = fsockopen ('sandbox.paypal.com', 443, $errno, $errstr, 30);

    //error connecting to paypal
    if (!$fp) {
        error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . $errno . " - " . $errstr . PHP_EOL, 3, LOG_FILE);
    }

    //successful connection    
    if ($fp) {
        fputs ($fp, $header . $req);

        while (!feof($fp)) {
            $res = fgets ($fp, 1024);
            $res = trim($res); //NEW & IMPORTANT

            if ($debug) {
                error_log(date('[Y-m-d H:i e] '). "DEBUG: Validation - " . $res . PHP_EOL, 3, LOG_FILE);
                error_log(date('[Y-m-d H:i e] '). "DEBUG: Payment Status - " . $payment_status . PHP_EOL, 3, LOG_FILE);
                error_log(date('[Y-m-d H:i e] '). "DEBUG: Receiver Email - " . $receiver_email . PHP_EOL, 3, LOG_FILE);
                error_log(date('[Y-m-d H:i e] '). "DEBUG: Verify Email - " . $verfiy_email . PHP_EOL, 3, LOG_FILE);
            }

            //I don't see this
            if (strcmp($res, "VERIFIED") == 0) {
                //insert order into database    
                if ($debug) {
                    error_log(date('[Y-m-d H:i e] '). "Response Message: " . "VERIFIED" . PHP_EOL, 3, LOG_FILE);
                }
            }

            //I don't see this
            if (strcmp ($res, "INVALID") == 0) {
                //insert into DB in a table for bad payments for you to process later
                if ($debug) {
                    error_log(date('[Y-m-d H:i e] '). "Response Message: " . "INVALID" . PHP_EOL, 3, LOG_FILE);
                }
            }

            if (strcasecmp ($payment_status, "Completed") == 0 && strcasecmp($receiver_email, $verfiy_email) == 0) {
                if ($debug) {
                    error_log(date('[Y-m-d H:i e] '). "Response Message: " . "Payment VERIFIED" . PHP_EOL, 3, LOG_FILE);
                }
            } else {
                if ($debug) {
                    error_log(date('[Y-m-d H:i e] '). "Response Message: " . "Payment INVALID" . PHP_EOL, 3, LOG_FILE);
                }
            }
        }

        fclose($fp);
    }
?>

【问题讨论】:

  • 如果您的服务器环境不支持 TLS,这意味着它必须很旧。像10岁以上。如果他们无法让您进入具有更新环境且运行 TLS 的新服务器,我强烈建议您切换主机。
  • 好的,所以我解决了我的问题,但现在 $res 始终为空白。我没有收到 VERIFIED 或 INVALID 回复。

标签: php paypal paypal-ipn fsockopen


【解决方案1】:

$res 在请求响应中循环,有时读取 1024 字节,在最后一次迭代时将其保留为空。

如果您尝试通过循环在某处记录$res 变量,您只会逐行找到响应,例如。

HTTP/1.0 302 Found 
Location: https://www.sandbox.paypal.com
Server: BigIP
Connection: close 

这不是解决问题,而是......只是一个想法。 :)

【讨论】:

    【解决方案2】:

    感谢您的发帖!我在发送 IPN 时遇到了类似的问题,我的服务器使用 fsocket 对其进行了验证,执行了代码以写入数据库,但 PayPal 在重试多次导致我的数据库中出现重复后仍然报告了“失败”的“交付状态”。查看您的代码后,我发现我一直在编写的教程忽略了这一行,导致来自 PayPal 的请求超时而不是显示 200:

        $header .= "Connection: close\r\n";
    

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,沙盒返回一个空结果。我的代码和 Tsukasa 提供的 Update 2 类似。

      我不得不将 sandbox.paypal.com 更改为 ipnbp.sandbox.paypal.com,并在其前面加上 ssl。 fsocket 调用如下所示:

      $fp = fsockopen ('ssl://ipnbp.sandbox.paypal.com', 443, $errno, $errstr, 30);
      

      【讨论】:

        猜你喜欢
        • 2019-02-13
        • 2011-06-17
        • 2011-11-14
        • 2012-02-02
        • 2016-04-29
        • 2013-04-01
        • 2014-07-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多