1

TLDR:由于某种原因,我无法通过商家验证,我认为可能是


一个多月以来,我一直在努力让我的 Apple Pay 应用程序正常工作,最终决定寻求帮助。


我在构建时遇到的错误:

1:curlError:“无法设置私钥文件:'/home2/mattmson/public_html/gwApplePayDev/certs/gwApplePay.key.pem'类型PEM”

2: Unhandled Promise Rejection: InvalidAccessError: The object does not support the operation or argument


我从 curl_test.php 文件中得到的错误:

    cURL Error 
35 - error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
 Verbose information 
*   Trying 17.171.78.7:443...
* Connected to apple-pay-gateway.apple.com (17.171.78.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
* Closing connection 0
  1. 证书有问题(遵循https://github.com/norfolkmustard/ApplePayJS的教程)
  2. 我的服务器上的文件权限有问题
  3. 我的 cUrl 尝试有问题

这是我的 index.php 文件

<?php
require_once ('my-path-to/apple_pay_conf.php');
?>
<!DOCTYPE html>
<html lang="en-GB">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>ApplePay Test</title>
<style>
#applePay {  
    width: 150px;  
    height: 50px;  
    display: none;   
    border-radius: 5px;    
    margin-left: auto;
    margin-right: auto;
    margin-top: 20px;
    background-image: -webkit-named-image(apple-pay-logo-white); 
    background-position: 50% 50%;
    background-color: black;
    background-size: 60%; 
    background-repeat: no-repeat;  
}
</style>
</head>
<body>
<div>
<button type="button" id="applePay"></button>
<p style="display:none" id="got_notactive">ApplePay is possible on this browser, but not currently activated.</p>
<p style="display:none" id="notgot">ApplePay is not available on this browser</p>
<p style="display:none" id="success">Test transaction completed, thanks. <a href="<?=$_SERVER["SCRIPT_URL"]?>">reset</a></p>
</div>
<script type="text/javascript">

var debug = <?=DEBUG?>;

if (window.ApplePaySession) {
   var merchantIdentifier = '<?=PRODUCTION_MERCHANTIDENTIFIER?>';
   var promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier);
   promise.then(function (canMakePayments) {
      if (canMakePayments) {
         document.getElementById("applePay").style.display = "block";
         logit('hi, I can do ApplePay');
      } else {   
         document.getElementById("got_notactive").style.display = "block";
         logit('ApplePay is possible on this browser, but not currently activated.');
      }
    }); 
} else {
    logit('ApplePay is not available on this browser');
    document.getElementById("notgot").style.display = "block";
}

document.getElementById("applePay").onclick = function(evt) {

     var runningAmount  = 42;
     var runningPP      = 0; getShippingCosts('domestic_std', true);
     var runningTotal   = function() { return runningAmount + runningPP; }
     var shippingOption = "";
     
     var subTotalDescr  = "Test Goodies";
     
     function getShippingOptions(shippingCountry){
     logit('getShippingOptions: ' + shippingCountry );
        if( shippingCountry.toUpperCase() == "<?=PRODUCTION_COUNTRYCODE?>" ) {
            shippingOption = [{label: 'Standard Shipping', amount: getShippingCosts('domestic_std', true), detail: '3-5 days', identifier: 'domestic_std'},{label: 'Expedited Shipping', amount: getShippingCosts('domestic_exp', false), detail: '1-3 days', identifier: 'domestic_exp'}];
        } else {
            shippingOption = [{label: 'International Shipping', amount: getShippingCosts('international', true), detail: '5-10 days', identifier: 'international'}];
        }
     
     }
     
     function getShippingCosts(shippingIdentifier, updateRunningPP ){
     
        var shippingCost = 0;
        
             switch(shippingIdentifier) {
        case 'domestic_std':
            shippingCost = 3;
            break;
        case 'domestic_exp':
            shippingCost = 6;
            break;
        case 'international':
            shippingCost = 9;
            break;
        default:
            shippingCost = 11;
            }
        
        if (updateRunningPP == true) {
            runningPP = shippingCost;
        }
            
        logit('getShippingCosts: ' + shippingIdentifier + " - " + shippingCost +"|"+ runningPP );
        
        return shippingCost;
     
     }

     var paymentRequest = {
       currencyCode: '<?=PRODUCTION_CURRENCYCODE?>',
       countryCode: '<?=PRODUCTION_COUNTRYCODE?>',
       requiredShippingContactFields: ['postalAddress'],
       //requiredShippingContactFields: ['postalAddress','email', 'name', 'phone'],
       //requiredBillingContactFields: ['postalAddress','email', 'name', 'phone'],
       lineItems: [{label: subTotalDescr, amount: runningAmount }, {label: 'P&P', amount: runningPP }],
       total: {
          label: '<?=PRODUCTION_DISPLAYNAME?>',
          amount: runningTotal()
       },
       supportedNetworks: ['amex', 'masterCard', 'visa' ],
       merchantCapabilities: [ 'supports3DS', 'supportsEMV', 'supportsCredit', 'supportsDebit' ]
    };
    
    var session = new ApplePaySession(1, paymentRequest);
    
    // Merchant Validation
    session.onvalidatemerchant = function (event) {
        logit(event);
        var promise = performValidation(event.validationURL);
        promise.then(function (merchantSession) {
            session.completeMerchantValidation(merchantSession);
        }); 
    }
    

    function performValidation(valURL) {
        return new Promise(function(resolve, reject) {
            console.log('hello');
            var xhr = new XMLHttpRequest();
            xhr.onload = function() {
                var data = JSON.parse(this.responseText);
                logit(data);
                resolve(data);
            };
            xhr.onerror = reject;
            xhr.open('GET', 'https://mywebsite.com/gwApplePayDev/apple_pay_comm.php?u=' + valURL);
            xhr.send();
        });
    }

    session.onshippingcontactselected = function(event) {
        logit('starting session.onshippingcontactselected');
        logit('NB: At this stage, apple only reveals the Country, Locality and 4 characters of the PostCode to protect the privacy of what is only a *prospective* customer at this point. This is enough for you to determine shipping costs, but not the full address of the customer.');
        logit(event);
        
        getShippingOptions( event.shippingContact.countryCode );
        
        var status = ApplePaySession.STATUS_SUCCESS;
        var newShippingMethods = shippingOption;
        var newTotal = { type: 'final', label: '<?=PRODUCTION_DISPLAYNAME?>', amount: runningTotal() };
        var newLineItems =[{type: 'final',label: subTotalDescr, amount: runningAmount }, {type: 'final',label: 'P&P', amount: runningPP }];
        
        session.completeShippingContactSelection(status, newShippingMethods, newTotal, newLineItems );
        
        
    }
    
    session.onshippingmethodselected = function(event) {
        logit('starting session.onshippingmethodselected');
        logit(event);
        
        getShippingCosts( event.shippingMethod.identifier, true );
        
        var status = ApplePaySession.STATUS_SUCCESS;
        var newTotal = { type: 'final', label: '<?=PRODUCTION_DISPLAYNAME?>', amount: runningTotal() };
        var newLineItems =[{type: 'final',label: subTotalDescr, amount: runningAmount }, {type: 'final',label: 'P&P', amount: runningPP }];
        
        session.completeShippingMethodSelection(status, newTotal, newLineItems );
        
        
    }
    
    session.onpaymentmethodselected = function(event) {
        logit('starting session.onpaymentmethodselected');
        logit(event);
        
        var newTotal = { type: 'final', label: '<?=PRODUCTION_DISPLAYNAME?>', amount: runningTotal() };
        var newLineItems =[{type: 'final',label: subTotalDescr, amount: runningAmount }, {type: 'final',label: 'P&P', amount: runningPP }];
        
        session.completePaymentMethodSelection( newTotal, newLineItems );
        
        
    }
    
    session.onpaymentauthorized = function (event) {

        logit('starting session.onpaymentauthorized');
        logit('NB: This is the first stage when you get the *full shipping address* of the customer, in the event.payment.shippingContact object');
        logit(event);

        var promise = sendPaymentToken(event.payment.token);
        promise.then(function (success) {   
            var status;
            if (success){
                status = ApplePaySession.STATUS_SUCCESS;
                document.getElementById("applePay").style.display = "none";
                document.getElementById("success").style.display = "block";
            } else {
                status = ApplePaySession.STATUS_FAILURE;
            }
            
            logit( "result of sendPaymentToken() function =  " + success );
            session.completePayment(status);
        });
    }

    function sendPaymentToken(paymentToken) {
        return new Promise(function(resolve, reject) {
            logit('starting function sendPaymentToken()');
            logit(paymentToken);
            
            logit("this is where you would pass the payment token to your third-party payment provider to use the token to charge the card. Only if your provider tells you the payment was successful should you return a resolve(true) here. Otherwise reject;");
            logit("defaulting to resolve(true) here, just to show what a successfully completed transaction flow looks like");
            if ( debug == true )
            resolve(true);
            else
            reject;
        });
    }
    
    session.oncancel = function(event) {
        logit('starting session.cancel');
        logit(event);
    }
    
    session.begin();

};
    
function logit( data ){
    
    if( debug == true ){
        console.log(data);
    }   

};
</script>
</body>
</html>

这是我的 apple_pay_conf.php 文件的代码

    <?php
    // update these with the real location of your two .pem files. keep them above/outside your webroot folder
    define('PRODUCTION_CERTIFICATE_KEY', 'path-to/certs/apple_pay.crt.pem');
    define('PRODUCTION_CERTIFICATE_PATH', 'path-to/certs/merch_id.crt.pem');
    
    define('PRODUCTION_CERTIFICATE_KEY_PASS', 'password'); 
    
    
    define('PRODUCTION_MERCHANTIDENTIFIER', 'merchant.com.mysite.myCompany');
    
    define('PRODUCTION_DOMAINNAME', 'mysite.com');
    
    
    define('PRODUCTION_CURRENCYCODE', 'USD');   // https://en.wikipedia.org/wiki/ISO_4217
    define('PRODUCTION_COUNTRYCODE', 'US');     // https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
    define('PRODUCTION_DISPLAYNAME', 'My Company');
    
    define('DEBUG', 'true');
    ?>

这是我的curl_test.php文件

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);

if (!function_exists('json_last_error_msg')) {
        function json_last_error_msg() {
            static $ERRORS = array(
                JSON_ERROR_NONE => 'No error',
                JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
                JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)',
                JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
                JSON_ERROR_SYNTAX => 'Syntax error',
                JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
            );

            $error = json_last_error();
            return isset($ERRORS[$error]) ? $ERRORS[$error] : 'Unknown error';
        }
    }

$validation_url = isset( $_GET['u'] ) ? $_GET['u'] : "https://apple-pay-gateway.apple.com/paymentservices/paymentSession";


if( "https" == parse_url($validation_url, PHP_URL_SCHEME) && substr( parse_url($validation_url, PHP_URL_HOST), -10 )  == ".apple.com" ){

    require_once ('mypathto/apple_pay_conf.php');
    
    if( !defined( 'DEBUG' ) || DEBUG != 'true' ) { exit( 'this page intentionally left blank' ); }
    
        echo "<pre>";
        
        // create a new cURL resource
        $ch = curl_init();
    
        $data = '{"merchantIdentifier":"'.PRODUCTION_MERCHANTIDENTIFIER.'", "domainName":"'.PRODUCTION_DOMAINNAME.'", "displayName":"'.PRODUCTION_DISPLAYNAME.'"}';
        
        echo "<fieldset style='padding:1em;margin:1em'><legend> data sent to applePay server </legend>$data</fieldset>";
    
        curl_setopt($ch, CURLOPT_URL, $validation_url);
        //curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'ecdhe_rsa_aes_128_gcm_sha_256,rsa_aes_128_gcm_sha_256');
        curl_setopt($ch, CURLOPT_SSLCERT, PRODUCTION_CERTIFICATE_PATH);
        curl_setopt($ch, CURLOPT_SSLKEY, PRODUCTION_CERTIFICATE_KEY);
        curl_setopt($ch, CURLOPT_SSLKEYPASSWD, PRODUCTION_CERTIFICATE_KEY_PASS);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        
        //debug options
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        $verbose = fopen('php://temp', 'w+');
        curl_setopt($ch, CURLOPT_STDERR, $verbose);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        $result = curl_exec($ch);
    
        if( $result === false)
        {
    
            echo "<fieldset style='padding:1em;margin:1em'><legend> cURL Error </legend>";
            echo curl_errno($ch) . " - " . curl_error($ch);
            echo "</fieldset>";
            
        } else {
            
            echo "<fieldset style='padding:1em;margin:1em'><legend> applePay server response </legend>";
            echo $result;
            echo "</fieldset>";
            
            echo "<fieldset style='padding:1em;margin:1em'><legend> applePay server response - JSON decode test </legend>";
            print_r( json_decode( $result, true ) );
            echo "<hr> JSON decode last error :- ";
            echo json_last_error_msg();
            echo "</fieldset>";
        }
    
        // close cURL resource, and free up system resources
        
        rewind($verbose);
        $verboseLog = stream_get_contents($verbose);
        
        echo "<fieldset style='padding:1em;margin:1em'><legend> Verbose information </legend>";
        echo htmlspecialchars($verboseLog);
        echo "</fieldset>";
        
        $version = curl_version();
        echo "<fieldset style='padding:1em;margin:1em'><legend> curl version </legend>";
        print_r( $version );
        echo "</fieldset></pre>";
            
        curl_close($ch);
        
    }
    ?>

任何帮助将不胜感激

4

0 回答 0