{"id":19506317,"url":"https://github.com/thenorthmemory/easyalipay","last_synced_at":"2025-04-26T02:32:33.997Z","repository":{"id":56974272,"uuid":"395916452","full_name":"TheNorthMemory/easyalipay","owner":"TheNorthMemory","description":"支付宝 [A]Sync Chainable Alipay OpenAPI SDK for PHP","archived":false,"fork":false,"pushed_at":"2023-01-10T06:36:25.000Z","size":102,"stargazers_count":20,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-02T03:06:45.833Z","etag":null,"topics":["alipay","chainable-openapi","openapi-sdk"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheNorthMemory.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-08-14T06:37:38.000Z","updated_at":"2024-06-04T09:30:38.000Z","dependencies_parsed_at":"2023-02-08T17:25:15.155Z","dependency_job_id":null,"html_url":"https://github.com/TheNorthMemory/easyalipay","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Feasyalipay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Feasyalipay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Feasyalipay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Feasyalipay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheNorthMemory","download_url":"https://codeload.github.com/TheNorthMemory/easyalipay/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224023528,"owners_count":17242989,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alipay","chainable-openapi","openapi-sdk"],"created_at":"2024-11-10T22:36:39.012Z","updated_at":"2024-11-10T22:36:40.721Z","avatar_url":"https://github.com/TheNorthMemory.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 支付宝 Alipay OpenAPI SDK\n\n[A]Sync Chainable Alipay OpenAPI SDK for PHP\n\n[![GitHub actions](https://github.com/TheNorthMemory/easyalipay/workflows/CI/badge.svg)](https://github.com/TheNorthMemory/easyalipay/actions)\n[![Version](https://img.shields.io/packagist/v/easyalipay/easyalipay)](https://packagist.org/packages/easyalipay/easyalipay)\n[![PHP Version](https://img.shields.io/packagist/php-v/easyalipay/easyalipay)](https://packagist.org/packages/easyalipay/easyalipay)\n[![License](https://img.shields.io/packagist/l/easyalipay/easyalipay)](https://packagist.org/packages/easyalipay/easyalipay)\n\n## 概览\n\n支付宝 OpenAPI 的[Guzzle HttpClient](http://docs.guzzlephp.org/)封装组合，\n内置 `请求签名` 和 `应答验签` 两个middlewares中间件，创新性地实现了链式面向对象同步/异步调用远程接口。\n\n如果你是使用 `Guzzle` 的商户开发者，可以使用 `EasyAlipay\\Builder::factory` 工厂方法直接创建一个 `GuzzleHttp\\Client` 的链式调用封装器，\n实例在执行请求时将自动携带身份认证信息，并检查应答的支付宝的返回签名。\n\n## 环境要求\n\n我们开发和测试使用的环境如下：\n\n+ PHP \u003e=7.1.2\n+ guzzlehttp/guzzle ^6.5 || ^7.0\n\n**注:**\n\n- 兼容支持`Guzzle6`的PHP最低版本为`7.1.2`，另PHP官方已于`1 Dec 2019`停止维护`PHP7.1`，详见附注链接；\n- 随`Guzzle7`支持的PHP最低版本为`7.2.5`，另PHP官方已于`30 Nov 2020`停止维护`PHP7.2`，详见附注链接；\n\n## 安装\n\n推荐使用PHP包管理工具`composer`引入SDK到项目中：\n\n### 方式一\n\n在项目目录中，通过composer命令行添加：\n\n```shell\ncomposer require easyalipay/easyalipay\n```\n\n### 方式二\n\n在项目的`composer.json`中加入以下配置：\n\n```json\n\"require\": {\n    \"easyalipay/easyalipay\": \"^0.3\"\n}\n```\n\n添加配置后，执行安装\n\n```shell\ncomposer install\n```\n\n## 约定\n\n本类库是以 `OpenAPI` `公共请求参数`中的接入方法 `method` 以`.`做切分，映射成`attributes`，编码书写方式有如下约定：\n\n1. 请求 接入方法 `method` 切分后的每个`attributes`，可直接以对象获取形式串接，例如 `alipay.trade.query` 即串成 `alipay-\u003etrade-\u003equery`;\n2. 每个 接入方法 `method` 所支持的 `HTTP METHOD`，即作为被串接对象的末尾执行方法，例如: `alipay-\u003etrade-\u003equery-\u003epost(['content' =\u003e []])`;\n3. 每个 接入方法 `method` 所支持的 `HTTP METHOD`，同时支持`Async`语法糖，例如: `alipay-\u003etrade-\u003equery-\u003epostAsync(['content' =\u003e []])`;\n4. 每个 接入方法 `method` 可以使用`PascalCase`风格书写，例如: `alipay.trade.query`可写成 `AlipayTradeQuery`;\n5. 在IDE集成环境下，也可以按照内置的`chain($method)`接口规范，直接以接入方法 `method`作为变量入参，来获取`OpenAPI`当前接入方法的实例，驱动末尾执行方法(填入对应参数)，发起请求，例如 `chain('alipay.trade.query')-\u003epost(['content' =\u003e []])`；\n6. 末尾`get`/`post`/`getAsync`/`postAsync`请求方法语法糖，型参`$options`语法糖规则如下：\n   1. `content`字典，对应的是`请求参数集合(biz_content)`字典，直接写原生`PHP array`即可；\n   2. `query`字典，对应的是除`请求参数集合(biz_content)`之外的，如部分特殊`公共请求参数(system_params)`有`通知地址(notify_url)`等，直接写原生`PHP array`即可；\n   3. 一个入参时`$options`按需带入`'content' =\u003e []` 及/或 `'query' =\u003e []`结构即可；\n   4. 简写语法糖支持`[get|post][Async](array $content, array $options)`、`[get|post][Async](array $content, array $query, array $options)`结构；\n   5. 本SDK所有`请求数据结构`遵循官方开发文档，该是蛇型即蛇形(如:`service_code`)，该是驼峰就驼峰(如:`shopIds`)，看到的数据结构，即`请求数据结构`，原生`PHP`语法即可；\n7. 内置`返回值验签`中间件在解构原始`json`字符串后，直接返回`*_response`对应的内容，有可能是`json`，也可能是`AesCbc`加密串，按需对返回串做处理；\n\n以下示例用法，以`异步(Async/PromiseA+)`或`同步(Sync)`结合此种编码模式展开。\n\n## 开始\n\n首先，通过 `EasyAlipay\\Builder::factory` 工厂方法构建一个实例，然后如上述`约定`，链式`同步`或`异步`请求远端`OpenAPI`接口。\n\n```php\nuse EasyAlipay\\Builder;\nuse EasyAlipay\\Crypto\\Rsa;\n\n//应用app_id\n$appId = '2014072300007148';\n\n//商户RSA私钥，入参是'从官方工具获取到的BASE64字符串'\n$privateKey = Rsa::fromPkcs1('MIIEpAIBAAKCAQEApdXuft3as2x...');\n// 以上是下列代码的语法糖，格式为 'private.pkcs1://' + '从官方工具获取到的字符串'\n// $privateKey = Rsa::from('private.pkcs1://MIIEpAIBAAKCAQEApdXuft3as2x...');\n// 也支持以下方式，须保证`private_key.pem`为完整X509格式\n// $privateKey = Rsa::from('file:///your/openapi/private_key.pem');\n\n//支付宝RSA公钥，入参是'从官方工具获取到的BASE64字符串'\n$publicKey = Rsa::fromSpki('MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg...');\n// 以上是下列代码的语法糖，格式为 'public.spki://' + '从官方工具获取到的字符串'\n// $publicKey = Rsa::from('public.spki://MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg...', Rsa::KEY_TYPE_PUBLIC);\n// 也支持以下方式，须保证`public_key.pem`为完整X509格式\n// $publicKey = Rsa::from('file:///the/alipay/public_key.pem', Rsa::KEY_TYPE_PUBLIC);\n\n//如果是公钥证书模式，可以在工厂方法内传入 `$appCertSn` 及 `$alipayRootCertSn`\n// $appCertFilePath = '/my/cert/app_cert.crt';\n// $appCertSn = \\EasyAlipay\\Helpers::sn($appCertFilePath);\n// $alipayRootCertFilePath = '/alipay/cert/alipayRootCert.crt';\n// $alipayRootCertSn = \\EasyAlipay\\Helpers::sn($alipayRootCertFilePath);\n\n// 工厂方法构造一个实例\n$instance = Builder::factory([\n    'privateKey' =\u003e $privateKey,\n    'publicKey' =\u003e $publicKey,\n    'params' =\u003e [\n        'app_id' =\u003e $appId,\n        // 'app_auth_token' =\u003e $appAuthToken,\n        // 'app_cert_sn' =\u003e $appCertSn,\n        // 'alipay_root_cert_sn' =\u003e $alipayRootCertSn,\n    ],\n]);\n```\n\n初始化字典说明如下：\n\n- `privateKey` 为`商户API私钥`，一般是通过官方证书生成工具生成字符串，支持`PKCS#1`及`PKCS#8`格式的私钥加载；\n- `publicKey` 为`平台API公钥`，一般是通过官方证书生成工具生成字符串，支持`PKCS#8`及`SPKI`格式的公钥加载；\n- `params` 接口中的`公共请求参数`配置项，已内置`charset=UTF-8`, `format=JSON`, `sign_type=RSA2`及`version=1.0`；\n- `params['app_id' =\u003e $appId]` 为你的`应用app_id`；\n- `params['app_auth_token' =\u003e $appAuthToken]` 为你的`ISV`模式的授权`token`，按需配置；\n- `params['app_cert_sn' =\u003e $appCertSn]` 为`公钥证书模式`的商户证书相关信息`SN`，按需配置；\n- `params['alipay_root_cert_sn' =\u003e $alipayRootCertSn]` 为`公钥证书模式`的平台证书相关信息`SN`，按需配置；\n\n**注：** `OpenAPI` 以及 `GuzzleHttp\\Client` 的 `array $config` 初始化参数，均融合在一个型参上。\n\n### 统一收单线下交易查询\n\n```php\nuse GuzzleHttp\\Utils;\nuse GuzzleHttp\\Exception\\RequestException;\n\ntry {\n    $res = $instance\n    -\u003ealipay-\u003etrade-\u003equery\n    -\u003eget(['content' =\u003e [\n        'out_trade_no' =\u003e '20150320010101001',\n    ]]);\n\n    echo $res-\u003egetBody(), PHP_EOL;\n} catch (RequestException $e) {\n    // 进行错误处理\n    if ($e-\u003ehasResponse()) {\n        $r = $e-\u003egetResponse();\n        echo $r-\u003egetStatusCode() . ' ' . $r-\u003egetReasonPhrase(), PHP_EOL;\n        echo $r-\u003egetBody(), PHP_EOL, PHP_EOL, PHP_EOL;\n    }\n} catch (\\Throwable $e) {\n    // 进行错误处理\n    echo $e-\u003egetMessage(), PHP_EOL;\n    echo $e-\u003egetTraceAsString(), PHP_EOL;\n}\n```\n\n### 统一收单交易支付接口\n\n```php\nuse GuzzleHttp\\Utils;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n$res = $instance\n-\u003ealipay-\u003etrade-\u003epay\n-\u003epostAsync(['content' =\u003e [\n    'out_trade_no' =\u003e '20150320010101001',\n    'scene'        =\u003e 'bar_code',\n    'auth_code'    =\u003e '28763443825664394',\n    'product_code' =\u003e 'FACE_TO_FACE_PAYMENT',\n    'subject'      =\u003e 'Iphone6 16G',\n    'total_amount' =\u003e '88.88',\n]])\n-\u003ethen(static function(ResponseInterface $response) {\n    // 正常逻辑回调处理\n    return Utils::jsonDecode((string) $response-\u003egetBody(), true);\n})\n-\u003eotherwise(static function($e) {\n    // 异常错误处理\n    echo $e-\u003egetMessage(), PHP_EOL;\n    if ($e instanceof RequestException \u0026\u0026 $e-\u003ehasResponse()) {\n        $r = $e-\u003egetResponse();\n        echo $r-\u003egetStatusCode() . ' ' . $r-\u003egetReasonPhrase(), PHP_EOL;\n        echo $r-\u003egetBody(), PHP_EOL, PHP_EOL, PHP_EOL;\n    }\n    echo $e-\u003egetTraceAsString(), PHP_EOL;\n})\n-\u003ewait();\nprint_r($res);\n```\n\n### 统一收单线下交易预创建\n\n```php\nuse GuzzleHttp\\Utils;\nuse GuzzleHttp\\Exception\\RequestException;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n$res = $instance\n-\u003eAlipay-\u003eTrade-\u003ePrecreate\n-\u003epostAsync([\n    'out_trade_no' =\u003e '20150320010101001',\n    'subject'      =\u003e 'Iphone6 16G',\n    'total_amount' =\u003e '88.88',\n], ['query' =\u003e [\n    'notify_url' =\u003e 'http://api.test.alipay.net/atinterface/receive_notify.htm'\n]])\n-\u003ethen(static function(ResponseInterface $response) {\n    // 正常逻辑回调处理\n    return Utils::jsonDecode((string) $response-\u003egetBody(), true);\n})\n-\u003eotherwise(static function($e) {\n    // 异常错误处理\n})\n-\u003ewait();\nprint_r($res);\n```\n\n### 手机网站支付接口2.0\n\n```php\nuse Psr\\Http\\Message\\ResponseInterface;\n\n$res = $instance\n-\u003echain('alipay.trade.wap.pay')\n-\u003epostAsync([\n    'subject'      =\u003e '商品名称',\n    'out_trade_no' =\u003e '22',\n    'total_amount' =\u003e '0.01',\n    'product_code' =\u003e 'FAST_INSTANT_TRADE_PAY',\n    'quit_url'     =\u003e 'https://forum.alipay.com/mini-app/post/15501011',\n], ['pager' =\u003e true])\n-\u003ethen(static function(ResponseInterface $response) {\n    // 正常逻辑回调处理\n    return (string) $response-\u003egetBody();\n})\n-\u003eotherwise(static function($e) {\n    // 异常错误处理\n})\n-\u003ewait();\nprint_r($res);\n```\n\n### 统一收单下单并支付页面接口\n\n```php\nuse GuzzleHttp\\Utils;\nuse GuzzleHttp\\Exception\\RequestException;\n\ntry {\n    $res = $instance['alipay.trade.page.pay']\n    -\u003epost(['content' =\u003e [\n        'subject'      =\u003e '商品名称',\n        'out_trade_no' =\u003e '22',\n        'total_amount' =\u003e '0.01',\n        'product_code' =\u003e 'FAST_INSTANT_TRADE_PAY',\n    ], 'pager' =\u003e true]);\n    echo $resp-\u003egetBody(), PHP_EOL;\n} catch (RequestException $e) {\n    // 进行错误处理\n} catch (\\Throwable $e) {\n    // 异常错误处理\n}\n```\n\n### 上传门店照片和视频接口\n\n```php\nuse GuzzleHttp\\Utils;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr\\MultipartStream;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n$media = new MultipartStream([\n    'name'     =\u003e 'image_content',\n    'contents' =\u003e 'file:///path/for/uploading.jpg',\n]);\n\n$res = $instance\n-\u003echain('alipay.offline.material.image.upload')\n-\u003epostAsync([\n    'body' =\u003e $media,\n])\n-\u003ethen(static function(ResponseInterface $response) {\n    // 正常逻辑回调处理\n    return Utils::jsonDecode((string) $response-\u003egetBody(), true);\n})\n-\u003eotherwise(static function($e) {\n    // 异常错误处理\n})\n-\u003ewait();\nprint_r($res);\n```\n\n### 敏感信息加/解密\n\n```php\nuse EasyAlipay\\Crypto\\AesCbc;\nuse GuzzleHttp\\Utils;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n$aesCipherKey = '';\n\n$res = $instance\n-\u003echain('some.method.response.by.aes.encrypted')\n-\u003epostAsync([])\n-\u003ethen(static function(ResponseInterface $response) use ($aesCipherKey) {\n    $json = Utils::jsonDecode((string) $response-\u003egetBody());\n    return AesCbc::decrypt((string) $json-\u003eresponse, $aesCipherKey);\n})\n-\u003ewait();\nprint_r($res);\n```\n\n## 链接\n\n- [变更历史](CHANGELOG.md)\n- [更多示例代码](./docs/README.md)\n- [GuzzleHttp官方版本支持](https://docs.guzzlephp.org/en/stable/overview.html#requirements)\n- [PHP官方版本支持](https://www.php.net/supported-versions.php)\n\n## 许可证\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenorthmemory%2Feasyalipay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthenorthmemory%2Feasyalipay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenorthmemory%2Feasyalipay/lists"}