Commit 7af2a6b6 authored by 杨培's avatar 杨培

Create

parents
<?php
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 17:59
*/
function internalApiAutoloader($className) {
if (substr($className, 0, 12) == 'internalApi\\') {
$file = dirname(__DIR__).DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $className).'.php';
if (is_file($file)) {
require $file;
}
}
}
spl_autoload_register('internalApiAutoloader');
<?php
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 10:06
*/
namespace internalApi\base;
abstract class Client
{
public $debug = false;
public $name;
protected $clientId;
protected $clientSecret;
protected $apiUrl;
protected static $instance = [];
protected static $config = [];
protected static function getInstance()
{
$className = static::class;
if (!isset(self::$instance[$className])) {
self::$instance[$className] = new $className();
}
return self::$instance[$className];
}
public function __construct()
{
$className = static::class;
$subName = strstr($className, '\\');
$name = substr($subName, 1, strpos($subName, '\\', 1)-1);
if (isset(static::$config[$name])) {
foreach (static::$config[$name] as $k => $v) {
if ($this->$k === null) {
$this->$k = $v;
}
}
}
foreach (['clientId', 'clientSecret', 'apiUrl'] as $prop) {
if ($this->$prop === null) {
throw new ClientException(static::class." initialize failed, \${$prop} not set!");
}
}
$this->name = $name;
}
public static function setDebug($debug=true)
{
$instance = self::getInstance();
$instance->debug = $debug;
}
public static function config($config)
{
self::$config = $config;
}
/**
* 调用请求,获取数据
*
* @param string $api
* @param array $params
* @return array
* @throws ClientException
*/
protected static function call($api, $params=[])
{
$instance = self::getInstance();
$url = $instance->apiUrl.(strpos($instance->apiUrl, '?') !== false ? '&' : '?').'api='.urlencode($api);
list($sign, $timestamp, $nonce) = $instance->signature($api, $params);
$url .= "&id={$instance->clientId}&sign={$sign}&timestamp={$timestamp}&nonce={$nonce}";
list($httpCode, $response) = $instance->request($url, $params);
if ($httpCode == 403 && substr($response, 0, 6) === 'error:') {
$message = substr($response, 6);
throw new ClientException("接口 $api 调用失败: " . $message);
} elseif ($httpCode != 200 || !$response) {
throw new ClientException('接口请求异常', $httpCode);
}
$data = @json_decode($response, true);
if (!is_array($data)) {
throw new ClientException('接口返回数据异常: ' . $response);
}
return $data;
}
/**
* 对请求进程签名
*
* @param string $api
* @param array $params
* @return array
*/
protected function signature($api, $params)
{
$timestamp = time();
$nonce = uniqid();
ksort($params);
$str = $api.http_build_query($params).$this->clientId.$this->clientSecret.$timestamp.$nonce;
$sign = md5($str);
return [$sign, $timestamp, $nonce];
}
protected function request($url, $post = '', $headers = array()) {
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_USERAGENT, 'PHP/'.PHP_VERSION.' Client/'.$this->clientId);
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 8);
curl_setopt($ci, CURLOPT_TIMEOUT, 8);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, false);
//curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
curl_setopt($ci, CURLOPT_HEADER, FALSE);
curl_setopt($ci, CURLOPT_POST, TRUE);
$post = is_array($post) ? http_build_query($post) : $post;
$post && curl_setopt($ci, CURLOPT_POSTFIELDS, $post);
curl_setopt($ci, CURLOPT_URL, $url);
curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE);
$response = curl_exec($ci);
$httpCode = curl_getinfo($ci, CURLINFO_HTTP_CODE);
$this->debug && $httpInfo = curl_getinfo($ci);
curl_close($ci);
if ($this->debug) {
echo '<pre>';
echo '=====info====='."\r\n";
print_r($httpInfo);
echo $url;
echo "\r\n=====post data======\r\n";
var_dump($post);
echo "\r\n=====response=====\r\n";
print_r($response);
echo '</pre>';
exit;
}
return [$httpCode, $response];
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 15:37
*/
namespace internalApi\base;
class ClientException extends \ErrorException
{
}
\ No newline at end of file
<?php
namespace internalApi\base;
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 10:06
*/
class Server
{
protected $apiMap = [];
protected $secret;
public function __construct($secret)
{
$this->secret = $secret;
}
public function setApiMap($map)
{
$this->apiMap = $map;
}
public function addApiMap($map)
{
foreach ($map as $key => $list) {
if (!isset($this->apiMap[$key])) {
$this->apiMap[$key] = [];
}
foreach ($list as $name => $callable) {
if (isset($this->apiMap[$key][$name])) {
continue;
}
$this->apiMap[$key][$name] = $callable;
}
}
}
/**
* Invoke API and get data
*
* @param bool $return
* @return array
* @throws
*/
public function invoke($return=false)
{
$api = $this->checkSign();
if (!$api) {
$this->responseError('鉴权失败');
}
$arr = explode('.', $api);
if (count($arr) != 2) {
$this->responseError('错误的 API 名称');
}
list($group, $name) = $arr;
if (!isset($this->apiMap[$group]) || !isset($this->apiMap[$group][$name])) {
$this->responseError('API 不存在');
}
$callable = $this->apiMap[$group][$name][0];
if (!is_callable($callable)) {
$this->responseError('API 无法调用');
}
$paramsList = array_slice($this->apiMap[$group][$name], 1);
$params = [];
foreach ($paramsList as $k => $v) {
if (is_int($k)) {
$k = $v;
$hasDefault = false;
} else {
$hasDefault = true;
}
if (isset($_POST[$k])) {
$params[] = $_POST[$k];
} elseif ($hasDefault) {
$params[] = $v;
} else {
$this->responseError('缺少参数 '.$k);
}
}
$data = call_user_func_array($callable, $params);
return $return ? $data : null;
}
public function responseError($message)
{
header('HTTP/1.0 403 Forbidden');
echo 'error:'.$message;
exit;
}
protected function checkSign()
{
$api = isset($_GET['api']) ? $_GET['api'] : '';
$clientId = isset($_GET['id']) ? $_GET['id'] : null;
$sign = isset($_GET['sign']) ? $_GET['sign'] : '';
$timestamp = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$nonce = isset($_GET['nonce']) ? $_GET['nonce'] : '';
$servTime = time();
$params = $_POST;
ksort($params);
$str = $api.http_build_query($params).$clientId.$this->secret.$timestamp.$nonce;
$servSign = md5($str);
if ($servSign !== $sign) {
return false;
}
if ($servTime - $timestamp > 300) {
return false;
}
return $api;
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 16:44
*/
namespace internalApi\base;
class ServerException extends \Exception
{
}
\ No newline at end of file
<?php
/**
* 内部 API 客户端调用演示
*/
use internalApi\ucenter\Member;
//首先需要初始化客户端,传入配置
//配置的保存位置根据项目决定,只需最终调用 Client::config() 传入即可
$internalApiClientConfig = [
'ucenter' => [
'apiUrl' => 'http://u.yunya.com/test/api-server',
'clientId' => 'common',
'clientSecret' => 'Kuy2dVHKRWKAFRXX2l6k'
],
'xue' => [
'apiUrl' => 'http://u.yunya.com/test/api-server',
'clientId' => 'common',
'clientSecret' => 'Kuy2dVHKRWKAFRXX2l6k'
]
];
\internalApi\base\Client::config($internalApiClientConfig);
//调用API
$user = Member::getMemberInfo(12);
var_dump($user);
\ No newline at end of file
<?php
/**
* 内部 API 服务端使用演示
*/
//初始化API
$internalApiServerSecret = 'Kuy2dVHKRWKAFRXX2l6k';
$server = new \internalApi\base\Server($internalApiServerSecret);
/**
* 设置 API 列表,setApiMap 会覆盖所有已有的 API 设置
*
* API 以此形式定义
* [
* '组' => [
* '名称' => [Callable, 第一个参数名, 第二个参数名, 第三个参数名=>参数默认值],
* '名称' => [Callable, 第一个参数名, 第二个参数名, 第三个参数名=>参数默认值]
* ]
* ]
*
* 其中 Callable 为一个可调用名称,参见 php 的 Callable 和闭包
* 参数必须严格按照 Callable 的参数顺序写好,如果定义键名,则键名为参数名称,键值为默认值,有默认值的参数在客户端调用时可不传
*/
$server->setApiMap([
'courseList' => [
'recommendList' => ['\common\course::fetchCommendList', 'page', 'num'=>20],
'newCourseList' => ['\common\course::fetchNewList', 'page'=>1, 'num'=>20]
],
'otherApi' => [
'getLink' => ['\other\Api\Common::getLink']
]
]);
//添加 API 列表,addApiMap 只会对已有 API 列表新增,但性能较差,建议 setApiMap 一次性设置好
$server->addApiMap([
'member' => [
'getInfo' => ['\common\models\Member::findByUid', 'uid']
]
]);
//启动调用
$server->invoke();
//如果想获得返回数据自己做些处理,使用 $data = $server->invoke(true) 即可
\ No newline at end of file
<?php
namespace internalApi\ucenter;
use internalApi\base\Client;
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 15:57
*/
class Member extends Client
{
public static function getMemberInfo($uid)
{
return self::call('member.getInfo', compact('uid'));
}
}
\ No newline at end of file
<?php
namespace internalApi\xue;
use internalApi\base\Client;
/**
* Created by PhpStorm.
* User: pader
* Date: 2017/6/27
* Time: 14:49
*/
class CourseList extends Client
{
public static function getRecommendList($num=10, $page=1)
{
return self::call('courseList.recommendList', compact('num', 'page'));
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment