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
- 证书有问题(遵循https://github.com/norfolkmustard/ApplePayJS的教程)
- 我的服务器上的文件权限有问题
- 我的 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);
}
?>
任何帮助将不胜感激