在网上没有找到支付宝easysdk接口的对接详细说明,自己一步一步的摸索,其中使用chatgpt的帮助作用不少。
根据官方给的文档
需要执行composer require alipaysdk/easysdk:^2.0安装sdk。如果你的项目已经安装过其它扩展,可以先把vendor文件夹备份一份,我用的是laravel框架,先问问chatgpt一般应该在那个文件下执行这个命令:
执行以后报错:
PHP Fatal error: Uncaught Error: Call to undefined function Composer\XdebugHandler\putenv() in phar:///www/server/php/74/bin/composer/vendor/composer/xdebug-handler/src/Process.php:93
Stack trace:
#0 phar:///www/server/php/74/bin/composer/vendor/composer/xdebug-handler/src/Status.php(48): Composer\XdebugHandler\Process::setEnv()
#1 phar:///www/server/php/74/bin/composer/vendor/composer/xdebug-handler/src/XdebugHandler.php(83): Composer\XdebugHandler\Status->construct()
#2 phar:///www/server/php/74/bin/composer/bin/composer(16): Composer\XdebugHandler\XdebugHandler->construct()
#3 /www/server/php/74/bin/composer(24): require(‘…’) …
问chatgpt怎样解决:
重新执行安装命令又报错,报错和chatgpt回答如下:
宝塔上安装fileinfo扩展
其它的一些像似的报错就不贴在这里了,可以在这个地址查看。
sdk安装好后,把路由和控制器写好,控制器代码如下,其中写require '…/vendor/autoload.php’是因为我写在了自定义的一个目录,可以根据自己的情况来写。代码根据上面提到的官方文档的代码修改而来。
namespace App\Http\Controllers;require '../vendor/autoload.php';use Illuminate\Http\Request;use Alipay\EasySDK\Kernel\Factory;use Alipay\EasySDK\Kernel\Util\ResponseChecker;use Alipay\EasySDK\Kernel\Config;class AlipayController extends Controller{ public function createPayment() { //1. 设置参数(全局只需设置一次) Factory::setOptions($this->getOptions()); try { //2. 发起API调用(以支付能力下的统一收单交易创建接口为例) $result = Factory::payment()->common()->create("iPhone6 16G", "20230526235526001", "88.88", "2088102170439210"); $responseChecker = new ResponseChecker(); //3. 处理响应或异常 if ($responseChecker->success($result)) { // $payUrl = $result->qrCode; // header("Location: {$payUrl}"); $body = $result->body; //通过打印返回信息,跳转的支付宝支付页面 print($body); echo "调用成功". PHP_EOL; } else { echo "调用失败,原因:". $result->msg.",".$result->subMsg.PHP_EOL; } } catch (Exception $e) { echo "调用失败,". $e->getMessage(). PHP_EOL;; } } function getOptions() { $options = new Config(); $options->protocol = 'https'; $options->gatewayHost = 'openapi-sandbox.dl.alipaydev.com'; $options->signType = 'RSA2'; $options->appId = '202100012266727922'; $options->method = 'alipay.trade.page.pay'; // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 method $options->merchantPrivateKey = 'MIIEpQIBAAKCAQEAy5hoPV8cQQ8+4oj81S6/sMf7Q76qasDjnfcl5bvCR7jlqgxkqTLvp804bsNYCGLpxQzyO2gK08lO5B+HJPG2QHNLMxpoAJZ+BJpTgIUOAjgQLt/1aSnBq+kmK36msuiWKqCdN551rBIzGDSv0xg6L8oR2BAR1hqmSz5POLMkwFwMkwGnxrOrzBmF8ll5EwFQGtIesLUNf8fSJTXY70yddGYz/ojy77xRtuP1GaUSRgXcUh5JBx8048L8zMW2S8id1X+otNXmFDZeBJ+1zQvxQA9ustAbUMU4yb7Z0y7UxiB9Q+4Mg5bPkFMeFlQ6HE+N/qbZLCWOXU6TjKRUTOWXHwIDAQABAoIBAQCh2v7701H98uXWaHs/65NfMgzyNXD7v271FRdexN7V8As9He8kiCb4avDzNX8V47Te/8TPL450AjUirGHfH/34zO+6p8KIvRtgA2Rg5uZVI0bSTR+nxBeA2LCMoXpa/wbqypdSMTpxWmKeWrxxAHC5r1ZyQ4w6fyM27ElE1T5hYSA9bjK4kklJ3LnvdSFTrHOOLDvsLne56DOkakE+vhiQqzRVMpPLZZr+CjyeWJNSvt8cCGmJsmKj3eYE6Z3PRwqtzS7qiGtUnuOViat1qEp78LX8dnxu0D8SB5hYoivMd3qYbQUF1ZgYVGyqUW7iOUeM8bEeTLQ5XPwDwWJVFBzZAoGBAPd10Uyqr/ffz94xMM+9TlFIvIZ6535yjhIuMzP6PxLElKaCu1wc6lc3it8ajrvWCXNzbCE+55Ty3tGq6rymZAmv347dC30VXCtNQeP4r+ztdgi3WH8oqfGWpiEF3kqrqZYVleMKyp8uQZZC2ypWEM6RYTfYijC/Rh3KvGCkWoEtAoGBANKfEPAiE+YFSabAUr31NBKiRFJhxHCSOHW2pL+X8JRyO8S9PfEp8y/qChFy1Fm7m/Ur4UsEOgVa5esTUCeMfyqBvDPs5IQzmRkC8Lbzbc7fQgqAU6xERIDUPhFbhQEJh/Pkj0tnyzOkIN2goI48Vg8FI2b2s+L14EzBWpHBArD7AoGBANHWWT3Ou1rQsb6zLbXqy/+HUz4h+C00TJ7ECG059cQfaAHud5v7dQeyNJNNPN2w+OCqbnWelteqPyHB8j04RzojpcnKTRSrSTX61DXRSrT5A48Okf955unSmlsEU+QzvqFi+m/FVd43ZixZ0ukKhEP16V9mwn/lojpfEPBOTeSdAoGATNqyKY2lySdgyrIe/yW8TJhdado2/gS9CWcOEsN0jBZq7M1JDvkJvhAegGNwTRYCQKI0YVU3fsC+aNrxQp0nwfD5JdFpSTwyv0etYnTNOtGInaBZ5+A5RvErfNXyYICD1WEvUIqdQUjAnV6Bd6VYmb58PpQC6+xgXmGnlMvjGYUCgYEA7WM2pqo0YMV2tuZmAL7w6SC9EkJZLELGr5CUueDJiMCNX0mQbIqRSSUIJ/PdHvpbL/wXXS3ngk3aECjp2ZVvBroB4CFJB3zenm9w6iVYVyudR1QNAtaYe0fkpazK8HjG2n49sw2GkFvpYZQ/z2JMQhD4/48TzLg3KI1hKJET+xA='; // $options->alipayCertPath = '../vendor_ali/alipayPublicCert.crt'; // $options->alipayRootCertPath = '../vendor_ali/alipayRootCert.crt'; // $options->merchantCertPath = '../vendor_ali/appPublicCert.crt'; //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 $options->alipayPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhlQOG8TEwgQzjhf2obQ6Vt7RDBkRarcrAhh/xfzOIs64pafkwys9V1Tl9COnSRlW+0bUoB5OG8V+5kO1rXA8oyzKovOcLRdmX1HXsis3hxJtjIhPH7tv95BqCEkS4snw5jd5UPrM3RscGsJ85ZO7qK4m9qG0s6NAu2glQ1FexQtvfLr7aLucP3uwNOEgv92VyUQiRcMwJ8muTlALIbHMrrGpc6xghRNPSNW8mLi2jZwv8BbntKWt8MJIKxxeEdGM/ld+bDzruCNzvkFR4SgX7NdFVFAeYqSlbwiPtDlT/6jmW6hatamtWoyc0ZM+EpoNeuCu3ZSa1P9niN69d2PzewIDAQAB'; // $options->alipayPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwec3sj0MUmC/uTNiXcsMWi3nw3BG1MX4KAMPgq2Wk5CV2cRmkc8sXKuYLQ2VoFnokdZljUikyYWTS/BFsh8hIFK0xqETQmam9MC0exbLqDZOStMIxs9SoNLHdlH/m7/t9aZYAFasK3R4ixcHnJZyrBwrVAAc9ifFQqwGdeLCcHZO9pHGWfcmHCYRkt1MUe6LGRm9U7wBRvDUU8YKgK5D8ao10AaLgHHmZN+uVXTCwxBYGzwuu0MJugDhkJOmafaHvkcz9iuh4VUjHZT0Hbk3XCr9V7gHENHFs70OW34Yl2Ivlg9mc+vzyiEItPV6uzl+x6L/V8lYrq9OSci4RfboJwIDAQAB'; $options->gatewayUrl = "https://openapi-sandbox.dl.alipaydev.com/gateway.do"; //可设置异步通知接收服务地址(可选) $options->notifyUrl = "https://www.min-ti.com/alipayipn"; return $options; } }
用get方法(自己认为get方便调试,后面可以方便的还为更安全的post方法)访问这个方法报错:
AlibabaCloud\Tea\Exception\TeaUnableRetryError: Undefined array key "sign" in file /vendor/alipaysdk/easysdk/php/src/Payment/Common/Client.php on line 121#0 /app/Http/Controllers/AlipayController.php(20): Alipay\EasySDK\Payment\Common\Client->create()#1 /vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\Http\Controllers\AlipayController->createPayment()#2 /vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction()#3 /vendor/laravel/framework/src/Illuminate/Routing/Route.php(262): Illuminate\Routing\ControllerDispatcher->dispatch()
这个报错字面意思的key没有定义,在网上没能找到这个报错的解决方法,easysdk接口相关的文档也很少,问chatgpt也没有足够的信息来定位错误,只好打开报错文件的文件来调试定位报错,报错文件对应的方法为:
public function create($subject, $outTradeNo, $totalAmount, $buyerId){ $_runtime = [ "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), "httpProxy" => $this->_kernel->getConfig("httpProxy"), "connectTimeout" => 15000, "readTimeout" => 15000, "retry" => [ "maxAttempts" => 0 ] ]; $_lastRequest = null; $_lastException = null; $_now = time(); $_retryTimes = 0; while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { if ($_retryTimes > 0) { $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); if ($_backoffTime > 0) { Tea::sleep($_backoffTime); } } $_retryTimes = $_retryTimes + 1; try { $_request = new Request(); $systemParams = [ "method" => "alipay.trade.create", "app_id" => $this->_kernel->getConfig("appId"), "timestamp" => $this->_kernel->getTimestamp(), "format" => "json", "version" => "1.0", "alipay_sdk" => $this->_kernel->getSdkVersion(), "charset" => "UTF-8", "sign_type" => $this->_kernel->getConfig("signType"), "app_cert_sn" => $this->_kernel->getMerchantCertSN(), "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() ]; $bizParams = [ "subject" => $subject, "out_trade_no" => $outTradeNo, "total_amount" => $totalAmount, "buyer_id" => $buyerId ]; $textParams = []; $_request->protocol = $this->_kernel->getConfig("protocol"); $_request->method = "POST"; $_request->pathname = "/gateway.do"; $_request->headers = [ "host" => $this->_kernel->getConfig("gatewayHost"), "content-type" => "application/x-www-form-urlencoded;charset=utf-8" ]; $_request->query = $this->_kernel->sortMap(Tea::merge([ "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) ], $systemParams, $textParams)); $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); $_lastRequest = $_request; $_response= Tea::send($_request, $_runtime); $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.create"); if ($this->_kernel->isCertMode()) { if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); } } else { // var_dump($this->_kernel->getConfig("alipayPublicKey")); // echo "\n\n"; // var_dump($respMap); if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); } } throw new TeaError([ "message" => "验签失败,请检查支付宝公钥设置是否正确。" ]); } catch (Exception $e) { if (!($e instanceof TeaError)) { $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); } if (Tea::isRetryable($e)) { $_lastException = $e; continue; } throw $e; } } throw new TeaUnableRetryError($_lastRequest, $_lastException); }
错误是在最后一行抛出的,其中有一行明显与sign有关:
"sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey"))
将其打印键sign对应的值是有值的,这样又陷入困境,chatgpt和各种搜索引擎找答案都没有合适的,参考支付宝的标准接口也没有找到对应的情况(后面发现这里是这个接口最坑的地方,真实的报错其实不是这样的。)chatgpt虽然没有直接找到答案,还是起到了帮助,帮助解读这个报错方法的代码,减少了阅读代码的时间。
没有现成办法,采用了先注释掉其中一部分代码,看是否还是报这个错来定位具体的报错行,发现是在做这一个判断的时候报的错:
if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey")))
接着打印$respMap才发现真正的报错是这样的:
array(2) { [“http_body”]=> string(140) “{“alipay_trade_create_response”:{“code”:“40002”,“msg”:“Invalid Arguments”,“sub_code”:“isv.invalid-app-id”,“sub_msg”:“没有权限”}}” [“method”]=> string(19) “alipay.trade.create” }
检查对应的appid的账号是否申请了这支付功能和重新填写,之后也遇到appid不对,一一排查以后采用了沙箱账号调试成功!
然后改为pc网页支付,在控制器里面把:
$result = Factory::payment()->common()->create("iPhone6 16G", "20230526235526001", "88.88", "2088102170439210");
改为
$result = Factory::payment()->page()->pay("iPhone6 16G", "20230526235526001", "88.88", "完成支付返回地址");
如果是手机页面支付,改为
$result = Factory::payment()->wap()->pay("iPhone6 16G", "20230526235526001", "88.88", '中途关闭支付返回地址', "完成支付返回地址");
返回信息验证举例,假如返回的地址对应的方法为alipayreturnurl
public function alipayreturnurl(Request $request) { $data = $request->all(); $params = $request->query(); Factory::setOptions($this->getOptions()); $result = Factory::payment()->common()->verifyNotify($params); // 验证签名 if ($result) { // 验证通过,处理业务逻辑 } else { // 验证失败,不处理业务逻辑 } }
这样调试基本ok了,接着是功能细化了。
示例地址查看。
来源地址:https://blog.csdn.net/qq_17858343/article/details/130468529