# 如何开发接口 使用PhalApi专业版开发接口,非常简单,大致流程如下。 ## 目录结构 PhalApi Pro版的目录结构如下, ``` ./ ├── README.md # 简介 ├── bin # 脚本目录 ├── config # 配置目录 │   ├── app.php # 应用配置 │   ├── dbs.php # 数据库配置 │   ├── di.php # 依赖服务配置 │   └── sys.php #系统配置 ├── data # 数据库 │   └── phalapi_pro.sql # 数据库安装时的文件 ├── language # 翻译包 ├── pro_admin # 管理后台的前端源代码,基于iview-admin ├── pro_platform # 开放平台的前端源代码,基于iview-admin ├── public # 对外访问的目录 │   ├── admin # 管理后台访问入口(相当于pro_admin打包构建后的dist目录) │   ├── api # 接口访问入口(内分前台API和后台API) │   ├── docs # 离线生成的HTML接口文档 │   ├── docs.php # 在线版接口文档访问入口 │   ├── index.php │   ├── init.php # 全局初始化文件 │   ├── install # 安装向导(成功安装后建议删除此目录) │   ├── platform # 开放平台访问入口(相当于pro_platform打包构建后的dist目录) │   ├── static # 静态资源 │   ├── uploads # 上传目录(需要有写入权限) │   └── wiki # 技术文档 ├── runtime # 运行目录 │   ├── _install.lock # 安装锁定文件 │   ├── cache # 文件缓存 │   └── log # 文件日志 ├── sdk # SDK包 ├── src # 项目源代码,非常重要 │   ├── admin # 后台接口源代码(遵循ADM模式) │   ├── app # 开放平台接口源代码(遵循ADM模式) │   ├── base # 基础包源代码(放置底层公共的代码,不对外直接提供接口,即不提供Api层) │   ├── platform # 开放平台接口源代码(遵循ADM模式) │   ├── task # 计划任务接口源代码(遵循ADM模式) │   └── view # 页面模板目录(如接口文档) ├── tests # 单元测试 └── vendor # composer包,不需要手动修改,通过composer install/update可进行安装和更新 ``` PHP代码层次结构如下: ![](http://cdn7.okayapi.com/yesyesapi_20200416113656_6c74c2813bed5ce7f552c5ed2a1007cc.png) ## 编写Api接口层 如果需要编写开放接口,可以在./src/app/Api目录下新增一个PHP文件,类名和文件名一样(需要区分大小写)。并继承App\Common\Api基类即可。 例如开放接口的Hello World示例,接口文件是:./src/app/Api/HelloWorld.php,类名是:App\Api\HelloWorld,对接的接口服务名称是:App.HelloWorld.Say。 ```php array( 'nickname' => array('name' => 'nickname', 'desc' => '昵称'), ), ); } /** * 示例 * @desc 第一个前台接口示例 */ public function say() { $nickname = $this->nickname; return array('content' => 'Hello world!'); } } ``` 保存后,访问接口文档列表,可以看到以下新接口: ![](http://cdn7.okayapi.com/yesyesapi_20191231095424_6cdab6e1dbac43fd95726fa2033412e0.png) 同时在接口详情文档可以查看到相应的详细接口文档: ![](http://cdn7.okayapi.com/yesyesapi_20191231100511_05d90cae0288de0649d1476772142a15.png) 如果需要编写后台接口,则需要放置在./src/admin/Api目录下,并继承Admin\Common\Api基类。其他开发要求类似。 > 温馨提示:以下方法是系统保留的函数名,不以用于接口函数名称,否则会影响接口正常运行。系统保留接口函数名称有:tryToGetUid()、checkUserLogin()、tryToGetAppKey()、checkAppOnline()、getCurContext()、init()、createMemberValue()、getApiRules()、getApiCommonRules()、getRules()、filterCheck()、userCheck()、isServiceWhitelist()、equalOrIngore()。 ## 如何取消接口令牌验证? 默认情况下,前台接口需要进行```access_token```令牌验证,以保护接口不被非法请求。如果不需要对指定的接口进行验证,可以在配置文件./config/app.php中的service_whitelist白名单中添加接口。例如上面的HelloWorld接口不需要接口验证,可以在最后追加配置: ```php 'service_whitelist' => array( 'Site.Index', 'HelloWorld.Say', // 追加Hello World示例白名单 ), ``` 接口白名单配置,会取消过滤器,不进行任何校验和判断,此时不会相应调整应用的接口权限。如果需要让接口权限在界面上显示保持一致,可以配置接口权限规则。 > 温馨提示:配置接口白名单,开放平台和管理后台的接口权限显示不会影响。 ## 如何取消接口权限判断? + 如何取消全部接口权限判断? 可以修改./config/app.php里面的default_app_api_rigths_is_allow配置项为true,即可让开放接口默认拥有权限,相当于取消全部接口权限判断。 + 如何取消某个接口类的接口权限判断? 在你的接口具体子类中,重载```\App\Common\Api::userCheck()```方法,不进行任何操作即可。 ```php /** * 平台接口基类 */ class Api extends \App\Common\Api { /** * 进行接口权限判断 * @throws BadRequestException */ protected function userCheck() { // 不需要 } } ``` > 温馨提示:通过代码取消接口权限判断,开放平台和管理后台的接口权限显示不会影响。 + 如何取消一个接口的接口权限判断? 在你的接口具体子类中,重载```\App\Common\Api::userCheckActionWhitelist()```方法,返回不需要进行接口权限判断的接口白名单。 ```php 温馨提示:通过代码取消接口权限判断,开放平台和管理后台的接口权限显示不会影响。 ## 如何获取当前上下文信息? 如何获取当前上下文、登录会员ID和app_key? 在App\Common\Api接口基类中,已经封装了针对于当前上下文、登录会员ID和app_key等接口,方便项目快速开发。 以下是使用代码和相关说明。 ```php class HelloWorld extends Api { public function say() { // 获取会员ID,未登录时异常返回 $uid = $this->tryToGetUid(); // 获取会员ID,未登录时返回0 $uid = $this->tryToGetUid(false); // 检测会员是否已登录,未登录时异常返回 $this->checkUserLogin(); // 获取app_key,未指定时异常返回 $appKey = $this->tryToGetAppKey(); // 获取app_key,未指定时返回空字符串 $appKey = $this->tryToGetAppKey(false); // 检测是否已指定app_key $this->checkAppOnline(); // 获取当前上下文 $context = $this->getCurContext(); var_dump($context->getUid()); // 会员ID var_dump($context->getAppKey()); // app_key } } ```` ## 如何隐藏access_token参数? 如果不需要在接口文档上显示```access_token```参数,可以在接口参数规则里这样配置(设置is_doc_hide为true即可)。 ```php class HelloWorld extends Api { public function getRules() { return array( 'say' => array( 'accessToken' => array('name' => 'access_token', 'is_doc_hide' => true), ), ) } } ``` ## 编写Domain领域层 Domain领域层主要用于封装复杂的业务逻辑、规则和算法。此部分PHP代码放置在./src/app/Domain目录下。此部分根据不同项目的业务需求,具体开发即可。 ## 编写Model数据层 Model数据层主要用于操作MySQL数据库,全部的Model子类可继承Base\Model\Base基类,此基类封装了很多实用的方法和接口,极大减少了数据库封装的代码。例如对应配置表的配置Model类代码如下: ```php array('App', '新的顶级命名空间'), ``` 例如,加了Task命名空间后: ```php // 开放接口的命名空间,配置后可提供接口权限分配,可配置多个 'open_api_namespaces' => array('App', 'Task'), ``` 在管理后台可以自动管理该命名空间下的接口权限。 接口权限分配: ![](http://cdn7.okayapi.com/yesyesapi_20200416114254_3c9a241aa03b33b0b66911583c8bd568.jpg) 接口服务列表: ![](http://cdn7.okayapi.com/yesyesapi_20200416114450_1d98c314d1c0eef0f34aad607a4ce076.jpg) 在开放平台,开发者也可自动看到新增命名空间下的接口。 ![](http://cdn7.okayapi.com/yesyesapi_20200416114634_7ac7f4d70c1c4e138eac7206c2134e46.png) ## 如何隐藏接口? 和开源版一样,在接口类或方法中添加```@ignore```注释。 如: ```php 'Hello PhalApi Pro!'); } } ``` ## 如何开启接口参数加密传输? 为了保护客户端传递的参数不被外界非法获取,除了使用HTTPS协议外,也可以通过代码方式来增加。 在PhalApi专业版,你可以: ** 客户端RSA公钥加密传输API接口参数 + 服务端RSA私钥解密API接口参数。** ### 重要配置 首先,是RSA私钥和公钥的文件,分别是: + rsa私钥文件:./config/phalapi_pro_rsa.pri + rsa公钥文件:./config/phalapi_pro_rsa.pub 在项目启动或开始时,你可以更换以上RSA配置文件,项目开始使用后,不建议再更换。 其次,还可以开启./config/app.php配置文件中的encrypt_data公共参数,方便客户端查看可以传递此参数以及其格式要求说明。 ```php /** * 应用接口层的统一参数 */ 'apiCommonRules' => array( 'accessToken' => array('name' => 'access_token', 'default' => '', 'desc' => '访问令牌,仅当开启签名验证时需要传递,生成令牌可使用App.Auth.ApplyToken接口'), /** ----- 如果你需要使用第二套加密算法,请开启以下参数规则 ----- **/ // 'app_key' => array('name' => 'app_key', 'default' => '', 'desc' => 'app_key,用于区分客户端应用,首次接入需要创建应用并等待管理员审核通过'), // 'sign' => array('name' => 'sign', 'desc' => '动态签名,签名算法是:
'), // 'uid' => array('name' => 'uid', 'type' => 'int', 'default' => 0, 'desc' => ''), // 'accessToken' => array('name' => 'access_token', 'default' => '', 'desc' => '访问令牌,保留使用但不需要在文档上展示', 'is_doc_hide' => true), 'encryptData' => array('name' => 'encrypt_data', 'desc' => '客户端加密的接口,格式是:RSA公钥加密(base64编码(JSON原始数据))。开启后,同时支持原来普通的参数传递方式。'), ), ``` ### 客户端RSA公钥加密传输API接口参数 将rsa公钥文件:./config/phalapi_pro_rsa.pub提供给受信任的客户端开发人员,其中待加密的encrypt_data参数格式是: encrypt_data = RSA公钥加密(base64编码(JSON原始数据)) 也就是: + 第1步、把全部的原始参数通过JSON格式封装 + 第2步、对第1步结果进行base64编码 + 第3步、使用RSA公钥进行加密 + 第4步、得到encrypt_data 以下是PHP作为客户端编写的代码示例: ```php // 公钥加密-由客户端完成 $public_key = openssl_pkey_get_public(file_get_contents('./phalapi_pro_rsa.pub')); openssl_public_encrypt('{"name":"phalapi pro"}', $crypted, $public_key); $_REQUEST['encrypt_data'] = base64_encode($crypted); // K07LIy/V+cfZqfHgZpIPnmdkwlkFbTkyRXVXx2JfQrF3YFAIsFcHnC9TjGTezzyup2f0V24nYH71Uf3oXVIqz/X9wgPXW0AGAbJw4kDOIq9Jao5L0mG7t5FV/2DLzJ14qO6fvANv6e/Hy2pFBcKvHnQ8uRJ/wyAV+RpUAa21wCY6zzuo9OhS89NPZg4B4CUORR8SIuIqWTUlXHB0woFIfRiO/AKCGltc9oDkyzJFYVvgI0LwijkQUV9RoruCEx6EvmZY7OVLB5+AXwfnfFKKtCw3jucqHyclzXwCQoif8FXN1NzCNpYvwj7DbzqU/WzRgxnPgXQSyjbCDlw19BrWoQ== ``` 以上,原始的参数是:```{"name":"phalapi pro"}```,最后加密后的结果如上。 > 温馨提示:客户端可以把需要加密的参数放到encrypt_data,同时服务端接口也会继续支持原来原始参数的传递。两者重复时以加密的参数为准。 ### 服务端RSA私钥解密API接口参数 此部分由后端API接口自动完成。不影响原有的接口参数传递方式和接口参数规则配置。 ## composer的使用 PhalApi专业版和PhalApi 2.x开源一样,都是使用了composer,如果对PHP composer不熟悉,可以查看[Composer 中文网 / Packagist 中国全量镜像](https://www.phpcomposer.com/),简单来说,composer是 PHP 用来管理依赖(dependency)关系的工具。 由于国外镜像通常会很慢,本地使用时可以切换到中国镜像。执行以下命令: ``` $ composer config -g repo.packagist composer https://packagist.phpcomposer.com ``` ## 扩展阅读 更多内容请参考[PhalApi 2.x 开发文档](http://docs.phalapi.net/#/)。