代码初始化

This commit is contained in:
2025-08-07 20:21:47 +08:00
commit 50f3a2dbb0
2191 changed files with 374790 additions and 0 deletions

146
extend/AliPayV2/AliPay.php Normal file
View File

@@ -0,0 +1,146 @@
<?php
use think\Loader;
/**
* 支付宝插件 使用方法请查看同文件夹下的demo
* 目前已经支持电脑网站支付手机APP支付支付回调校验用户提现等功能如需拓展请联系作者
* @author Jack_YanTC <627495692@qq.com>
*/
class AliPay
{
private $appId;
private $rsaPrivateKey;
private $notifyUrl;
private $alipayPublicKey;
private $appCertPath;
private $alipayCertPath;
private $rootCertPath;
/**
* 初始化参数
*
*/
public function __construct()
{
$this->appCertPath = ADDON_PATH . 'epay/certs/appCertPublicKey_2021005162648430.crt';
$this->alipayCertPath = ADDON_PATH . 'epay/certs/alipayCertPublicKey_RSA2.crt';
$this->rootCertPath = ADDON_PATH . 'epay/certs/alipayRootCert.crt';
$configs = get_system_config();
$this->appId = $configs['alipay_app_id'];
$this->rsaPrivateKey = $configs['alipay_private_key'];
$this->alipayPublicKey = $configs['alipay_public_key'];
$this->notifyUrl = $configs['web_site']."/api/Payment/notify_ali";
$aliPayPath = EXTEND_PATH.'/AliPayV2/alipay-sdk/aopV2/';
require_once $aliPayPath . 'AopCertClient.php';
require_once $aliPayPath . 'AopClient.php';
require_once $aliPayPath . 'AopCertification.php';
require_once $aliPayPath . 'AlipayConfig.php';
require_once $aliPayPath . 'request/AlipaySystemOauthTokenRequest.php';
require_once $aliPayPath . 'request/AlipayUserInfoShareRequest.php';
require_once $aliPayPath . 'request/AlipayTradeAppPayRequest.php';
}
/**
* 支付宝手机网站支付
* @param string $orderid 订单号
* @param string $money 金额
* @param string $subject 标题
* @return string
*/
public function aliAppPays($orderid, $money, $subject)
{
$aop = new AopCertClient ();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = $this->appId;
$aop->rsaPrivateKey = $this->rsaPrivateKey;
$aop->alipayrsaPublicKey = $aop->getPublicKey($this->alipayCertPath);//调用getPublicKey从支付宝公钥证书中提取公钥
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset = 'utf-8';
$aop->format = 'json';
$aop->isCheckAlipayPublicCert = true;//是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
$aop->appCertSN = $aop->getCertSN($this->appCertPath);//调用getCertSN获取证书序列号
$aop->alipayRootCertSN = $aop->getRootCertSN($this->rootCertPath);//调用getRootCertSN获取支付宝根证书序列号
$request = new AlipayTradeAppPayRequest ();
$bizcontent = json_encode([
'subject' => $subject,
'out_trade_no' => $orderid,//此订单号为商户唯一订单号
'total_amount' => $money//保留两位小数
], JSON_UNESCAPED_UNICODE);
$request->setNotifyUrl($this->notifyUrl);
$request->setBizContent($bizcontent);
$result = $aop->sdkExecute($request);
return $result;
}
public function verify($post)
{
$aop = new AopCertClient ();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = $this->appId;
$aop->rsaPrivateKey = $this->rsaPrivateKey;
$aop->alipayrsaPublicKey = $aop->getPublicKey($this->alipayCertPath);//调用getPublicKey从支付宝公钥证书中提取公钥
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset = 'utf-8';
$aop->format = 'json';
$aop->isCheckAlipayPublicCert = true;//是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
$aop->appCertSN = $aop->getCertSN($this->appCertPath);//调用getCertSN获取证书序列号
$aop->alipayRootCertSN = $aop->getRootCertSN($this->rootCertPath);//调用getRootCertSN获取支付宝根证书序列号
return $aop->rsaCheckV1($post, NULL, "RSA2");
}
//支付宝换取访问令牌
public function login($auth_code)
{
$aop = new AopCertClient ();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = $this->appId;
$aop->rsaPrivateKey = $this->rsaPrivateKey;
$aop->alipayrsaPublicKey = $aop->getPublicKey($this->alipayCertPath);//调用getPublicKey从支付宝公钥证书中提取公钥
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset = 'utf-8';
$aop->format = 'json';
$aop->isCheckAlipayPublicCert = true;//是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
$aop->appCertSN = $aop->getCertSN($this->appCertPath);//调用getCertSN获取证书序列号
$aop->alipayRootCertSN = $aop->getRootCertSN($this->rootCertPath);//调用getRootCertSN获取支付宝根证书序列号
// 创建请求对象
$request = new AlipaySystemOauthTokenRequest();//AlipaySystemOauthTokenRequest
$request->setGrantType("authorization_code");
$request->setCode( $auth_code);
// 执行请求获取access_token
$result = $aop->execute($request);
if (isset( $result->alipay_system_oauth_token_response->access_token)) {
// 获取用户信息
$userinfo_request = new AlipayUserInfoShareRequest();
$userinfo_result = $aop->execute( $userinfo_request, $result->alipay_system_oauth_token_response->access_token);
if ($userinfo_result->alipay_user_info_share_response->code == '10000') {
// 处理用户信息,例如保存到数据库
$user_info = $userinfo_result->alipay_user_info_share_response;
return ['code'=>'1','msg'=>'success','data'=>$user_info];
} else {
// 处理错误
return ['code'=>$result->error_response->code,'msg'=>$result->error_response->msg.'/'.$result->error_response->sub_code,'data'=>$result->error_response->sub_msg];
}
} else {
// 处理错误
return ['code'=>$result->error_response->code,'msg'=>$result->error_response->msg.'/'.$result->error_response->sub_code,'data'=>$result->error_response->sub_msg];
}
}
}

View File

@@ -0,0 +1,197 @@
<?php
class AlipayConfig {
/**
* 网关地址
* 线上https://openapi.alipay.com/gateway.do
* 沙箱https://openapi.alipaydev.com/gateway.do
*/
private $serverUrl;
/**
* 开放平台上创建的应用的ID
*/
private $appId;
/**
* 报文格式推荐json
*/
private $format = "json";
/**
* 字符串编码推荐utf-8
*/
private $charset = "utf-8";
/**
* 签名算法类型推荐RSA2
*/
private $signType = "RSA2";
/**
* 商户私钥
*/
private $privateKey;
/**
* 支付宝公钥字符串(公钥模式下设置,证书模式下无需设置)
*/
private $alipayPublicKey;
/**
* 商户应用公钥证书路径(证书模式下设置,公钥模式下无需设置)
*/
private $appCertPath;
/**
* 支付宝公钥证书路径(证书模式下设置,公钥模式下无需设置)
*/
private $alipayPublicCertPath;
/**
* 支付宝根证书路径(证书模式下设置,公钥模式下无需设置)
*/
private $rootCertPath;
/**
* 指定商户公钥应用证书内容字符串该字段与appCertPath只需指定一个优先以该字段的值为准证书模式下设置公钥模式下无需设置
*/
private $appCertContent;
/**
* 指定支付宝公钥证书内容字符串该字段与alipayPublicCertPath只需指定一个优先以该字段的值为准证书模式下设置公钥模式下无需设置
*/
private $alipayPublicCertContent;
/**
* 指定根证书内容字符串该字段与rootCertPath只需指定一个优先以该字段的值为准证书模式下设置公钥模式下无需设置
*/
private $rootCertContent;
/**
* 敏感信息对称加密算法类型推荐AES
*/
private $encryptType = "AES";
/**
* 敏感信息对称加密算法密钥
*/
private $encryptKey;
/**
* 跳过加验签(小程序云免鉴权)
*/
private $skipSign = false;
public function getServerUrl() {
return $this->serverUrl;
}
public function setServerUrl($serverUrl) {
$this->serverUrl = $serverUrl;
}
public function getAppId(){
return $this->appId;
}
public function setAppId($appId){
$this->appId = $appId;
}
public function getFormat(){
return $this->format;
}
public function setFormat($format){
$this->format = $format;
}
public function getCharset() {
return $this->charset;
}
public function setCharset($charset) {
$this->charset = $charset;
}
public function getSignType() {
return $this->signType;
}
public function setSignType($signType) {
$this->signType = $signType;
}
public function getEncryptKey() {
return $this->encryptKey;
}
public function setEncryptKey($encryptKey) {
$this->encryptKey = $encryptKey;
}
public function getEncryptType() {
return $this->encryptType;
}
public function setEncryptType($encryptType) {
$this->encryptType = $encryptType;
}
public function getPrivateKey() {
return $this->privateKey;
}
public function setPrivateKey($privateKey) {
$this->privateKey = $privateKey;
}
public function getAlipayPublicKey() {
return $this->alipayPublicKey;
}
public function setAlipayPublicKey($alipayPublicKey) {
$this->alipayPublicKey = $alipayPublicKey;
}
public function getAppCertPath() {
return $this->appCertPath;
}
public function setAppCertPath($appCertPath) {
$this->appCertPath = $appCertPath;
}
public function getAlipayPublicCertPath() {
return $this->alipayPublicCertPath;
}
public function setAlipayPublicCertPath($alipayPublicCertPath) {
$this->alipayPublicCertPath = $alipayPublicCertPath;
}
public function getRootCertPath() {
return $this->rootCertPath;
}
public function setRootCertPath($rootCertPath) {
$this->rootCertPath = $rootCertPath;
}
public function getAppCertContent() {
return $this->appCertContent;
}
public function setAppCertContent($appCertContent) {
$this->appCertContent = $appCertContent;
}
public function getAlipayPublicCertContent() {
return $this->alipayPublicCertContent;
}
public function setAlipayPublicCertContent($alipayPublicCertContent) {
$this->alipayPublicCertContent = $alipayPublicCertContent;
}
public function getRootCertContent() {
return $this->rootCertContent;
}
public function setRootCertContent($rootCertContent) {
$this->rootCertContent = $rootCertContent;
}
public function isSkipSign()
{
return $this->skipSign;
}
public function setSkipSign(bool $skipSign)
{
$this->skipSign = $skipSign;
}
}

View File

@@ -0,0 +1,188 @@
<?php
/**
* 多媒体文件客户端
* @author yikai.hu
* @version $Id: AlipayMobilePublicMultiMediaClient.php, v 0.1 Aug 15, 2014 10:19:01 AM yikai.hu Exp $
*/
include("AlipayMobilePublicMultiMediaExecute.php");
class AlipayMobilePublicMultiMediaClient
{
private $DEFAULT_CHARSET = 'UTF-8';
private $METHOD_POST = "POST";
private $METHOD_GET = "GET";
private $SIGN = 'sign'; //get name
private $timeout = 10;// 超时时间
private $serverUrl;
private $appId;
private $privateKey;
private $prodCode;
private $format = 'json'; //todo
private $sign_type = 'RSA'; //todo
private $charset;
private $apiVersion = "1.0";
private $apiMethodName = "alipay.mobile.public.multimedia.download";
private $media_id = "L21pZnMvVDFQV3hYWGJKWFhYYUNucHJYP3Q9YW13ZiZ4c2lnPTU0MzRhYjg1ZTZjNWJmZTMxZGJiNjIzNDdjMzFkNzkw575";
//此处写死的,实际开发中,请传入
private $connectTimeout = 3000;
private $readTimeout = 15000;
function __construct($serverUrl = '', $appId = '', $partner_private_key = '', $format = '', $charset = 'GBK')
{
$this->serverUrl = $serverUrl;
$this->appId = $appId;
$this->privateKey = $partner_private_key;
$this->format = $format;
$this->charset = $charset;
}
/**
* getContents 获取网址内容
* @param $request
* @return text | bin
*/
public function getContents()
{
$datas = array(
"app_id" => $this->appId,
"method" => $this->METHOD_POST,
"sign_type" => $this->sign_type,
"version" => $this->apiVersion,
"timestamp" => date('Y-m-d H:i:s'),//yyyy-MM-dd HH:mm:ss
"biz_content" => '{"mediaId":"' . $this->media_id . '"}',
"charset" => $this->charset
);
//要提交的数据
$data_sign = $this->buildGetUrl($datas);
$post_data = $data_sign;
//初始化 curl
$ch = curl_init();
//设置目标服务器
curl_setopt($ch, CURLOPT_URL, $this->serverUrl);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
if ($this->METHOD_POST == 'POST') {
// post数据
curl_setopt($ch, CURLOPT_POST, 1);
// post的变量
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $output;
$datas = explode("\r\n\r\n", $output, 2);
$header = $datas[0];
if ($httpCode == '200') {
$body = $datas[1];
} else {
$body = '';
}
return $this->execute($header, $body, $httpCode);
}
/**
*
* @param $request
* @return text | bin
*/
public function execute($header = '', $body = '', $httpCode = '')
{
$exe = new AlipayMobilePublicMultiMediaExecute($header, $body, $httpCode);
return $exe;
}
public function buildGetUrl($query = array())
{
if (!is_array($query)) {
//exit;
}
//排序参数,
$data = $this->buildQuery($query);
// 私钥密码
$passphrase = '';
$key_width = 64;
//私钥
$privateKey = $this->privateKey;
$p_key = array();
//如果私钥是 1行
if (!stripos($privateKey, "\n")) {
$i = 0;
while ($key_str = substr($privateKey, $i * $key_width, $key_width)) {
$p_key[] = $key_str;
$i++;
}
} else {
//echo '一行?';
}
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
$privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";
//私钥
$private_id = openssl_pkey_get_private($privateKey, $passphrase);
// 签名
$signature = '';
if ("RSA2" == $this->sign_type) {
openssl_sign($data, $signature, $private_id, OPENSSL_ALGO_SHA256);
} else {
openssl_sign($data, $signature, $private_id, OPENSSL_ALGO_SHA1);
}
openssl_free_key($private_id);
//加密后的内容通常含有特殊字符,需要编码转换下
$signature = base64_encode($signature);
$signature = urlencode($signature);
//$signature = 'XjUN6YM1Mc9HXebKMv7GTLy7gmyhktyOgKk2/Jf+cz4DtP6udkzTdpkjW2j/Z4ZSD7xD6CNYI1Spz4yS93HPT0a5X9LgFWYY8SaADqe+ArXg+FBSiTwUz49SE//Xd9+LEiIRsSFkbpkuiGoO6mqJmB7vXjlD5lx6qCM3nb41wb8=';
$out = $data . '&' . $this->SIGN . '=' . $signature;
return $out;
}
/*
* 查询参数排序 a-z
* */
public function buildQuery($query)
{
if (!$query) {
return null;
}
//将要 参数 排序
ksort($query);
//重新组装参数
$params = array();
foreach ($query as $key => $value) {
$params[] = $key . '=' . $value;
}
$data = implode('&', $params);
return $data;
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* 多媒体文件客户端
* @author yuanwai.wang
* @version $Id: AlipayMobilePublicMultiMediaExecute.php, v 0.1 Aug 15, 2014 10:19:01 AM yuanwai.wang Exp $
*/
//namespace alipay\api ;
class AlipayMobilePublicMultiMediaExecute
{
private $code = 200;
private $msg = '';
private $body = '';
private $params = '';
private $fileSuffix = array(
"image/jpeg" => 'jpg', //+
"text/plain" => 'text'
);
/*
* @$header : 头部
* */
function __construct($header, $body, $httpCode)
{
$this->code = $httpCode;
$this->msg = '';
$this->params = $header;
$this->body = $body;
}
/**
*
* @return text | bin
*/
public function getCode()
{
return $this->code;
}
/**
*
* @return text | bin
*/
public function getMsg()
{
return $this->msg;
}
/**
*
* @return text | bin
*/
public function getType()
{
$subject = $this->params;
$pattern = '/Content\-Type:([^;]+)/';
preg_match($pattern, $subject, $matches);
if ($matches) {
$type = $matches[1];
} else {
$type = 'application/download';
}
return str_replace(' ', '', $type);
}
/**
*
* @return text | bin
*/
public function getContentLength()
{
$subject = $this->params;
$pattern = '/Content-Length:\s*([^\n]+)/';
preg_match($pattern, $subject, $matches);
return (int)(isset($matches[1]) ? $matches[1] : '');
}
public function getFileSuffix($fileType)
{
$type = isset($this->fileSuffix[$fileType]) ? $this->fileSuffix[$fileType] : 'text/plain';
if (!$type) {
$type = 'json';
}
return $type;
}
/**
*
* @return text | bin
*/
public function getBody()
{
//header('Content-type: image/jpeg');
return $this->body;
}
/**
* 获取参数
* @return text | bin
*/
public function getParams()
{
return $this->params;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,527 @@
<?php
/**
* 验证支付宝公钥证书是否可信
* @param $alipayCert 支付宝公钥证书
* @param $rootCert 支付宝根证书
*/
function isTrusted($alipayCert, $rootCert)
{
$alipayCerts = readPemCertChain($alipayCert);
$rootCerts = readPemCertChain($rootCert);
if (verifyCertChain($alipayCerts, $rootCerts)) {
return verifySignature($alipayCert, $rootCert);
} else {
return false;
}
}
function verifySignature($alipayCert, $rootCert)
{
$alipayCertArray = explode("-----END CERTIFICATE-----", $alipayCert);
$rootCertArray = explode("-----END CERTIFICATE-----", $rootCert);
$length = count($rootCertArray) - 1;
$checkSign = isCertSigner($alipayCertArray[0] . "-----END CERTIFICATE-----", $alipayCertArray[1] . "-----END CERTIFICATE-----");
if (!$checkSign) {
$checkSign = isCertSigner($alipayCertArray[1] . "-----END CERTIFICATE-----", $alipayCertArray[0] . "-----END CERTIFICATE-----");
if ($checkSign) {
$issuer = openssl_x509_parse($alipayCertArray[0] . "-----END CERTIFICATE-----")['issuer'];
for ($i = 0; $i < $length; $i++) {
$subject = openssl_x509_parse($rootCertArray[$i] . "-----END CERTIFICATE-----")['subject'];
if ($issuer == $subject) {
isCertSigner($alipayCertArray[0] . "-----END CERTIFICATE-----", $rootCertArray[$i] . $rootCertArray);
return $checkSign;
}
}
} else {
return $checkSign;
}
} else {
$issuer = openssl_x509_parse($alipayCertArray[1] . "-----END CERTIFICATE-----")['issuer'];
for ($i = 0; $i < $length; $i++) {
$subject = openssl_x509_parse($rootCertArray[$i] . "-----END CERTIFICATE-----")['subject'];
if ($issuer == $subject) {
$checkSign = isCertSigner($alipayCertArray[1] . "-----END CERTIFICATE-----", $rootCertArray[$i] . "-----END CERTIFICATE-----");
return $checkSign;
}
}
return $checkSign;
}
}
function readPemCertChain($cert)
{
$array = explode("-----END CERTIFICATE-----", $cert);
$certs[] = null;
for ($i = 0; $i < count($array) - 1; $i++) {
$certs[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
}
return $certs;
}
function verifyCert($prev, $rootCerts)
{
$nowTime = time();
if ($nowTime < $prev['validFrom_time_t']) {
echo "证书未激活";
return false;
}
if ($nowTime > $prev['validTo_time_t']) {
echo "证书已经过期";
return false;
}
$subjectMap = null;
for ($i = 0; $i < count($rootCerts); $i++) {
$subjectDN = array2string($rootCerts[$i]['subject']);
$subjectMap[$subjectDN] = $rootCerts[$i];
}
$issuerDN = array2string(($prev['issuer']));
if (!array_key_exists($issuerDN, $subjectMap)) {
echo "证书链验证失败";
return false;
}
return true;
}
/**
* 验证证书链是否是信任证书库中证书签发的
* @param $alipayCerts 目标验证证书列表
* @param $rootCerts 可信根证书列表
*/
function verifyCertChain($alipayCerts, $rootCerts)
{
$sorted = sortByDn($alipayCerts);
if (!$sorted) {
echo "证书链验证失败:不是完整的证书链";
return false;
}
//先验证第一个证书是不是信任库中证书签发的
$prev = $alipayCerts[0];
$firstOK = verifyCert($prev, $rootCerts);
$length = count($alipayCerts);
if (!$firstOK || $length == 1) {
return $firstOK;
}
$nowTime = time();
//验证证书链
for ($i = 1; $i < $length; $i++) {
$cert = $alipayCerts[$i];
if ($nowTime < $cert['validFrom_time_t']) {
echo "证书未激活";
return false;
}
if ($nowTime > $cert['validTo_time_t']) {
echo "证书已经过期";
return false;
}
}
return true;
}
/**
* 将证书链按照完整的签发顺序进行排序,排序后证书链为:[issuerA, subjectA]-[issuerA, subjectB]-[issuerB, subjectC]-[issuerC, subjectD]...
* @param $certs 证书链
*/
function sortByDn(&$certs)
{
//是否包含自签名证书
$hasSelfSignedCert = false;
$subjectMap = null;
$issuerMap = null;
for ($i = 0; $i < count($certs); $i++) {
if (isSelfSigned($certs[$i])) {
if ($hasSelfSignedCert) {
return false;
}
$hasSelfSignedCert = true;
}
$subjectDN = array2string($certs[$i]['subject']);
$issuerDN = array2string(($certs[$i]['issuer']));
$subjectMap[$subjectDN] = $certs[$i];
$issuerMap[$issuerDN] = $certs[$i];
}
$certChain = null;
addressingUp($subjectMap, $certChain, $certs[0]);
addressingDown($issuerMap, $certChain, $certs[0]);
//说明证书链不完整
if (count($certs) != count($certChain)) {
return false;
}
//将证书链复制到原先的数据
for ($i = 0; $i < count($certs); $i++) {
$certs[$i] = $certChain[count($certs) - $i - 1];
}
return true;
}
/**
* 验证证书是否是自签发的
* @param $cert 目标证书
*/
function isSelfSigned($cert)
{
$subjectDN = array2string($cert['subject']);
$issuerDN = array2string($cert['issuer']);
return ($subjectDN == $issuerDN);
}
function array2string($array)
{
$string = [];
if ($array && is_array($array)) {
foreach ($array as $key => $value) {
$string[] = $key . '=' . $value;
}
}
return implode(',', $string);
}
/**
* 向上构造证书链
* @param $subjectMap 主题和证书的映射
* @param $certChain 证书链
* @param $current 当前需要插入证书链的证书include
*/
function addressingUp($subjectMap, &$certChain, $current)
{
$certChain[] = $current;
if (isSelfSigned($current)) {
return;
}
$issuerDN = array2string($current['issuer']);
if (!array_key_exists($issuerDN, $subjectMap)) {
return;
}
addressingUp($subjectMap, $certChain, $subjectMap[$issuerDN]);
}
/**
* 向下构造证书链
* @param $issuerMap 签发者和证书的映射
* @param $certChain 证书链
* @param $current 当前需要插入证书链的证书exclude
*/
function addressingDown($issuerMap, &$certChain, $current)
{
$subjectDN = array2string($current['subject']);
if (!array_key_exists($subjectDN, $issuerMap)) {
return $certChain;
}
$certChain[] = $issuerMap[$subjectDN];
addressingDown($issuerMap, $certChain, $issuerMap[$subjectDN]);
}
/**
* Extract signature from der encoded cert.
* Expects x509 der encoded certificate consisting of a section container
* containing 2 sections and a bitstream. The bitstream contains the
* original encrypted signature, encrypted by the public key of the issuing
* signer.
* @param string $der
* @return string on success
* @return bool false on failures
*/
function extractSignature($der = false)
{
if (strlen($der) < 5) {
return false;
}
// skip container sequence
$der = substr($der, 4);
// now burn through two sequences and the return the final bitstream
while (strlen($der) > 1) {
$class = ord($der[0]);
$classHex = dechex($class);
switch ($class) {
// BITSTREAM
case 0x03:
$len = ord($der[1]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$i + 2]);
}
}
return substr($der, 3 + $bytes, $len);
break;
// SEQUENCE
case 0x30:
$len = ord($der[1]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$i + 2]);
}
}
$contents = substr($der, 2 + $bytes, $len);
$der = substr($der, 2 + $bytes + $len);
break;
default:
return false;
break;
}
}
return false;
}
/**
* Get signature algorithm oid from der encoded signature data.
* Expects decrypted signature data from a certificate in der format.
* This ASN1 data should contain the following structure:
* SEQUENCE
* SEQUENCE
* OID (signature algorithm)
* NULL
* OCTET STRING (signature hash)
* @return bool false on failures
* @return string oid
*/
function getSignatureAlgorithmOid($der = null)
{
// Validate this is the der we need...
if (!is_string($der) or strlen($der) < 5) {
return false;
}
$bit_seq1 = 0;
$bit_seq2 = 2;
$bit_oid = 4;
if (ord($der[$bit_seq1]) !== 0x30) {
die('Invalid DER passed to getSignatureAlgorithmOid()');
}
if (ord($der[$bit_seq2]) !== 0x30) {
die('Invalid DER passed to getSignatureAlgorithmOid()');
}
if (ord($der[$bit_oid]) !== 0x06) {
die('Invalid DER passed to getSignatureAlgorithmOid');
}
// strip out what we don't need and get the oid
$der = substr($der, $bit_oid);
// Get the oid
$len = ord($der[1]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$i + 2]);
}
}
$oid_data = substr($der, 2 + $bytes, $len);
// Unpack the OID
$oid = floor(ord($oid_data[0]) / 40);
$oid .= '.' . ord($oid_data[0]) % 40;
$value = 0;
$i = 1;
while ($i < strlen($oid_data)) {
$value = $value << 7;
$value = $value | (ord($oid_data[$i]) & 0x7f);
if (!(ord($oid_data[$i]) & 0x80)) {
$oid .= '.' . $value;
$value = 0;
}
$i++;
}
return $oid;
}
/**
* Get signature hash from der encoded signature data.
* Expects decrypted signature data from a certificate in der format.
* This ASN1 data should contain the following structure:
* SEQUENCE
* SEQUENCE
* OID (signature algorithm)
* NULL
* OCTET STRING (signature hash)
* @return bool false on failures
* @return string hash
*/
function getSignatureHash($der = null)
{
// Validate this is the der we need...
if (!is_string($der) or strlen($der) < 5) {
return false;
}
if (ord($der[0]) !== 0x30) {
die('Invalid DER passed to getSignatureHash()');
}
// strip out the container sequence
$der = substr($der, 2);
if (ord($der[0]) !== 0x30) {
die('Invalid DER passed to getSignatureHash()');
}
// Get the length of the first sequence so we can strip it out.
$len = ord($der[1]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$i + 2]);
}
}
$der = substr($der, 2 + $bytes + $len);
// Now we should have an octet string
if (ord($der[0]) !== 0x04) {
die('Invalid DER passed to getSignatureHash()');
}
$len = ord($der[1]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$i + 2]);
}
}
return bin2hex(substr($der, 2 + $bytes, $len));
}
/**
* Determine if one cert was used to sign another
* Note that more than one CA cert can give a positive result, some certs
* re-issue signing certs after having only changed the expiration dates.
* @param string $cert - PEM encoded cert
* @param string $caCert - PEM encoded cert that possibly signed $cert
* @return bool
*/
function isCertSigner($certPem = null, $caCertPem = null)
{
if (!function_exists('openssl_pkey_get_public')) {
die('Need the openssl_pkey_get_public() function.');
}
if (!function_exists('openssl_public_decrypt')) {
die('Need the openssl_public_decrypt() function.');
}
if (!function_exists('hash')) {
die('Need the php hash() function.');
}
if (empty($certPem) or empty($caCertPem)) {
return false;
}
// Convert the cert to der for feeding to extractSignature.
$certDer = pemToDer($certPem);
if (!is_string($certDer)) {
die('invalid certPem');
}
// Grab the encrypted signature from the der encoded cert.
$encryptedSig = extractSignature($certDer);
if (!is_string($encryptedSig)) {
die('Failed to extract encrypted signature from certPem.');
}
// Extract the public key from the ca cert, which is what has
// been used to encrypt the signature in the cert.
$pubKey = openssl_pkey_get_public($caCertPem);
if ($pubKey === false) {
die('Failed to extract the public key from the ca cert.');
}
// Attempt to decrypt the encrypted signature using the CA's public
// key, returning the decrypted signature in $decryptedSig. If
// it can't be decrypted, this ca was not used to sign it for sure...
$rc = openssl_public_decrypt($encryptedSig, $decryptedSig, $pubKey);
if ($rc === false) {
return false;
}
// We now have the decrypted signature, which is der encoded
// asn1 data containing the signature algorithm and signature hash.
// Now we need what was originally hashed by the issuer, which is
// the original DER encoded certificate without the issuer and
// signature information.
$origCert = stripSignerAsn($certDer);
if ($origCert === false) {
die('Failed to extract unsigned cert.');
}
// Get the oid of the signature hash algorithm, which is required
// to generate our own hash of the original cert. This hash is
// what will be compared to the issuers hash.
$oid = getSignatureAlgorithmOid($decryptedSig);
if ($oid === false) {
die('Failed to determine the signature algorithm.');
}
switch ($oid) {
case '1.2.840.113549.2.2':
$algo = 'md2';
break;
case '1.2.840.113549.2.4':
$algo = 'md4';
break;
case '1.2.840.113549.2.5':
$algo = 'md5';
break;
case '1.3.14.3.2.18':
$algo = 'sha';
break;
case '1.3.14.3.2.26':
$algo = 'sha1';
break;
case '2.16.840.1.101.3.4.2.1':
$algo = 'sha256';
break;
case '2.16.840.1.101.3.4.2.2':
$algo = 'sha384';
break;
case '2.16.840.1.101.3.4.2.3':
$algo = 'sha512';
break;
default:
die('Unknown signature hash algorithm oid: ' . $oid);
break;
}
// Get the issuer generated hash from the decrypted signature.
$decryptedHash = getSignatureHash($decryptedSig);
// Ok, hash the original unsigned cert with the same algorithm
// and if it matches $decryptedHash we have a winner.
$certHash = hash($algo, $origCert);
return ($decryptedHash === $certHash);
}
/**
* Convert pem encoded certificate to DER encoding
* @return string $derEncoded on success
* @return bool false on failures
*/
function pemToDer($pem = null)
{
if (!is_string($pem)) {
return false;
}
$cert_split = preg_split('/(-----((BEGIN)|(END)) CERTIFICATE-----)/', $pem);
if (!isset($cert_split[1])) {
return false;
}
return base64_decode($cert_split[1]);
}
/**
* Obtain der cert with issuer and signature sections stripped.
* @param string $der - der encoded certificate
* @return string $der on success
* @return bool false on failures.
*/
function stripSignerAsn($der = null)
{
if (!is_string($der) or strlen($der) < 8) {
return false;
}
$bit = 4;
$len = ord($der[($bit + 1)]);
$bytes = 0;
if ($len & 0x80) {
$bytes = $len & 0x0f;
$len = 0;
for ($i = 0; $i < $bytes; $i++) {
$len = ($len << 8) | ord($der[$bit + $i + 2]);
}
}
return substr($der, 4, $len + 4);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
<?php
/**
* 加密工具类
*
* User: jiehua
* Date: 16/3/30
* Time: 下午3:25
*/
/**
* 加密方法
* @param string $str
* @return string
*/
function encrypt($str, $screct_key)
{
//AES, 128 模式加密数据 CBC
$screct_key = base64_decode($screct_key);
$str = trim($str);
$str = addPKCS7Padding($str);
//设置全0的IV
$iv = str_repeat("\0", 16);
$encrypt_str = openssl_encrypt($str, 'aes-128-cbc', $screct_key, OPENSSL_NO_PADDING, $iv);
return base64_encode($encrypt_str);
}
/**
* 解密方法
* @param string $str
* @return string
*/
function decrypt($str, $screct_key)
{
//AES, 128 模式加密数据 CBC
$str = base64_decode($str);
$screct_key = base64_decode($screct_key);
//设置全0的IV
$iv = str_repeat("\0", 16);
$decrypt_str = openssl_decrypt($str, 'aes-128-cbc', $screct_key, OPENSSL_NO_PADDING, $iv);
$decrypt_str = stripPKSC7Padding($decrypt_str);
return $decrypt_str;
}
/**
* 填充算法
* @param string $source
* @return string
*/
function addPKCS7Padding($source)
{
$source = trim($source);
$block = 16;
$pad = $block - (strlen($source) % $block);
if ($pad <= $block) {
$char = chr($pad);
$source .= str_repeat($char, $pad);
}
return $source;
}
/**
* 移去填充算法
* @param string $source
* @return string
*/
function stripPKSC7Padding($source)
{
$char = substr($source, -1);
$num = ord($char);
if ($num == 62) return $source;
$source = substr($source, 0, -$num);
return $source;
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* TODO 补充说明
*
* User: jiehua
* Date: 16/3/30
* Time: 下午8:55
*/
class EncryptParseItem
{
public $startIndex;
public $endIndex;
public $encryptContent;
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* TODO 补充说明
*
* User: jiehua
* Date: 16/3/30
* Time: 下午8:51
*/
class EncryptResponseData
{
public $realContent;
public $returnContent;
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Created by PhpStorm.
* User: jiehua
* Date: 15/5/2
* Time: 下午6:21
*/
class SignData
{
public $signSourceData = null;
public $sign = null;
}

View File

@@ -0,0 +1,150 @@
<?php
/**
* ALIPAY API: alipay.system.oauth.token request
*
* @author auto create
* @since 1.0, 2024-03-01 16:28:47
*/
class AlipaySystemOauthTokenRequest
{
/**
* 授权码,用户对应用授权后得到。本参数在 grant_type 为 authorization_code 时必填;为 refresh_token 时不填。
**/
private $code;
/**
* 授权方式
**/
private $grantType;
/**
* 刷新令牌,上次换取访问令牌时得到。本参数在 grant_type 为 authorization_code 时不填;为 refresh_token 时必填,且该值来源于此接口的返回值 app_refresh_token即至少需要通过 grant_type=authorization_code 调用此接口一次才能获取)。
**/
private $refreshToken;
private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;
public function setCode($code)
{
$this->code = $code;
$this->apiParas["code"] = $code;
}
public function getCode()
{
return $this->code;
}
public function setGrantType($grantType)
{
$this->grantType = $grantType;
$this->apiParas["grant_type"] = $grantType;
}
public function getGrantType()
{
return $this->grantType;
}
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
$this->apiParas["refresh_token"] = $refreshToken;
}
public function getRefreshToken()
{
return $this->refreshToken;
}
public function getApiMethodName()
{
return "alipay.system.oauth.token";
}
public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}
public function getNotifyUrl()
{
return $this->notifyUrl;
}
public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}
public function getReturnUrl()
{
return $this->returnUrl;
}
public function getApiParas()
{
return $this->apiParas;
}
public function getTerminalType()
{
return $this->terminalType;
}
public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}
public function getTerminalInfo()
{
return $this->terminalInfo;
}
public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}
public function getProdCode()
{
return $this->prodCode;
}
public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}
public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}
public function getApiVersion()
{
return $this->apiVersion;
}
public function setNeedEncrypt($needEncrypt)
{
$this->needEncrypt=$needEncrypt;
}
public function getNeedEncrypt()
{
return $this->needEncrypt;
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* ALIPAY API: alipay.trade.app.pay request
*
* @author auto create
* @since 1.0, 2024-12-11 16:02:21
*/
class AlipayTradeAppPayRequest
{
/**
* app支付接口2.0
**/
private $bizContent;
private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;
public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}
public function getBizContent()
{
return $this->bizContent;
}
public function getApiMethodName()
{
return "alipay.trade.app.pay";
}
public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}
public function getNotifyUrl()
{
return $this->notifyUrl;
}
public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}
public function getReturnUrl()
{
return $this->returnUrl;
}
public function getApiParas()
{
return $this->apiParas;
}
public function getTerminalType()
{
return $this->terminalType;
}
public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}
public function getTerminalInfo()
{
return $this->terminalInfo;
}
public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}
public function getProdCode()
{
return $this->prodCode;
}
public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}
public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}
public function getApiVersion()
{
return $this->apiVersion;
}
public function setNeedEncrypt($needEncrypt)
{
$this->needEncrypt=$needEncrypt;
}
public function getNeedEncrypt()
{
return $this->needEncrypt;
}
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* ALIPAY API: alipay.trade.query request
*
* @author auto create
* @since 1.0, 2024-12-25 16:17:22
*/
class AlipayTradeQueryRequest
{
/**
* 统一收单线下交易查询
修改路由策略到R
**/
private $bizContent;
private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;
public function setBizContent($bizContent)
{
$this->bizContent = $bizContent;
$this->apiParas["biz_content"] = $bizContent;
}
public function getBizContent()
{
return $this->bizContent;
}
public function getApiMethodName()
{
return "alipay.trade.query";
}
public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}
public function getNotifyUrl()
{
return $this->notifyUrl;
}
public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}
public function getReturnUrl()
{
return $this->returnUrl;
}
public function getApiParas()
{
return $this->apiParas;
}
public function getTerminalType()
{
return $this->terminalType;
}
public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}
public function getTerminalInfo()
{
return $this->terminalInfo;
}
public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}
public function getProdCode()
{
return $this->prodCode;
}
public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}
public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}
public function getApiVersion()
{
return $this->apiVersion;
}
public function setNeedEncrypt($needEncrypt)
{
$this->needEncrypt=$needEncrypt;
}
public function getNeedEncrypt()
{
return $this->needEncrypt;
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* ALIPAY API: alipay.user.info.share request
*
* @author auto create
* @since 1.0, 2025-02-13 15:12:20
*/
class AlipayUserInfoShareRequest
{
private $apiParas = array();
private $terminalType;
private $terminalInfo;
private $prodCode;
private $apiVersion="1.0";
private $notifyUrl;
private $returnUrl;
private $needEncrypt=false;
public function getApiMethodName()
{
return "alipay.user.info.share";
}
public function setNotifyUrl($notifyUrl)
{
$this->notifyUrl=$notifyUrl;
}
public function getNotifyUrl()
{
return $this->notifyUrl;
}
public function setReturnUrl($returnUrl)
{
$this->returnUrl=$returnUrl;
}
public function getReturnUrl()
{
return $this->returnUrl;
}
public function getApiParas()
{
return $this->apiParas;
}
public function getTerminalType()
{
return $this->terminalType;
}
public function setTerminalType($terminalType)
{
$this->terminalType = $terminalType;
}
public function getTerminalInfo()
{
return $this->terminalInfo;
}
public function setTerminalInfo($terminalInfo)
{
$this->terminalInfo = $terminalInfo;
}
public function getProdCode()
{
return $this->prodCode;
}
public function setProdCode($prodCode)
{
$this->prodCode = $prodCode;
}
public function setApiVersion($apiVersion)
{
$this->apiVersion=$apiVersion;
}
public function getApiVersion()
{
return $this->apiVersion;
}
public function setNeedEncrypt($needEncrypt)
{
$this->needEncrypt=$needEncrypt;
}
public function getNeedEncrypt()
{
return $this->needEncrypt;
}
}

View File

@@ -0,0 +1,114 @@
<?php
class AttributeRule
{
private $type;
private $name;
private $value;
/**
* @param $name
* @param $type
* @param $value
*/
public function __construct($type = null, $name = null, $value = null)
{
$this->type = $type;
$this->name = $name;
$this->value = $value;
}
public function checkRuleType($ruleType)
{
$ruleTypeArr = array(
"required" => "是否必填,true/false",
"maxLength" => "字符串要求最大长度",
"minLength" => "字符串要求最小长度",
"exclusiveMaximum" => "最大值,包含最大值,<=",
"exclusiveMinimum" => "最小值,包含最小值,>=",
"maximum" => "最大值,不包含最大值,<",
"minimum" => "最小值,不包含最小值,>",
"maxSize" => "最大个数",
"minSize" => "最大个数",
"precision" => "精度",
"pattern" => "正则表达式",
"valueType" => "值类型",
"devTip" => "输入提示",
"height" => "高度",
"width" => "长度",
"urlSchema" => "url格式"
);
if (empty($ruleType)) return false;
if (array_key_exists($ruleType, $ruleTypeArr)) return true;
return false;
}
/**
* @throws Exception
*/
public function toElement($dom, $parent, $attributeId)
{
if (empty($this->name) && $this->name != '0') {
throw new \Exception("id=[" . $attributeId . "] AttrRule格式错误!AttrRule缺少name!");
}
if (!$this->checkRuleType($this->type)) {
throw new \Exception("id=[" . $attributeId . "] AttrRule类型type不合法!");
}
if (empty($this->value) && $this->value != '0') {
throw new \Exception("id=[" . $attributeId . "] AttrRule格式错误!AttrRule缺少value!");
}
$rule = $dom->createElement("rule");
$rule->setAttribute("name", $this->name);
$rule->setAttribute("type", $this->type);
$rule->setAttribute("value", $this->value);
$parent->appendChild($rule);
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
*/
public function setType($type)
{
$this->type = $type;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,66 @@
<?php
class Option
{
private $displayName;
private $value;
/**
* @param $displayName
* @param $value
*/
public function __construct($displayName = null, $value = null)
{
$this->displayName = $displayName;
$this->value = $value;
}
/**
* @throws Exception
*/
public function toElement($dom, $parent, $attributeId)
{
if (empty($this->displayName) && $this->displayName != '0') {
throw new \Exception("id=[" . $attributeId . "] Option格式错误!Option名称displayName不能为空!");
}
if (empty($this->value) && $this->value != '0') {
throw new \Exception("id=[" . $attributeId . "] Option格式错误!Option的值value不能为空!");
}
$option = $dom->createElement("option");
$option->setAttribute("displayName", $this->displayName);
$option->setAttribute("value", $this->value);
$parent->appendChild($option);
}
/**
* @return mixed
*/
public function getDisplayName()
{
return $this->displayName;
}
/**
* @param mixed $displayName
*/
public function setDisplayName($displayName)
{
$this->displayName = $displayName;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,27 @@
<?php
require_once 'XMLAttribute.php';
require_once 'AttributeRule.php';
require_once 'Option.php';
class ServiceSchemaFactory
{
public static function createAttribute($id = null, $name = null, $type = null, $valueType = null)
{
$attribute = new XMLAttribute();
$attribute->setId($id);
$attribute->setName($name);
$attribute->setType($type);
$attribute->setValueType($valueType);
return $attribute;
}
public static function createRule($type = null, $name = null, $value = null)
{
return new AttributeRule($type, $name, $value);
}
public static function createOption($displayName = null, $value = null)
{
return new Option($displayName, $value);
}
}

View File

@@ -0,0 +1,256 @@
<?php
require_once 'XMLAttribute.php';
require_once 'AttributeRule.php';
require_once 'Option.php';
require_once 'ServiceSchemaFactory.php';
class ServiceSchemaReader
{
/**
* @throws Exception
*/
public static function readXmlForArrayByFile($filePath)
{
set_error_handler('ServiceSchemaReader::errorHandler');
$dom = new DOMDocument('1.0', 'utf-8');
try {
$dom->load($filePath);
} catch (Exception $e) {
throw new \Exception("XML格式错误,无法正常解析!");
}
return self::readXmlForList($dom->documentElement);
}
/**
* @throws Exception
*/
public static function readXmlForArrayByString($xmlString)
{
set_error_handler('ServiceSchemaReader::errorHandler');
$dom = new DOMDocument('1.0', 'utf-8');
try {
$dom->loadXML($xmlString);
} catch (Exception $e) {
throw new \Exception("XML格式错误,无法正常解析!");
}
return self::readXmlForList($dom->documentElement);
}
/**
* @throws Exception
*/
public static function readXmlForList(DOMElement $rootEle)
{
$attributeArr = array();
foreach ($rootEle->getElementsByTagName('attribute') as $item) {
if ($item->parentNode === $rootEle) {
$attribute = self::elementToAttribute($item);
$attributeArr[$attribute->getId()] = $attribute;
}
}
return $attributeArr;
}
/**
* @throws Exception
*/
public static function elementToAttribute($attributeElm)
{
$attributeId = $attributeElm->getAttribute("id");
if (self::checkEmpty($attributeId)) {
throw new \Exception("Attribute属性缺少id! 节点路径 [" . $attributeElm->getNodePath() . "]");
}
$attributeName = $attributeElm->getAttribute("name");
$attributeType = $attributeElm->getAttribute("type");
if (self::checkEmpty($attributeType)) {
throw new \Exception("Attribute属性缺少type! 节点路径 [" . $attributeElm->getNodePath() . "].attributeId=" . $attributeId);
}
$valueType = $attributeElm->getAttribute("valueType");
$attribute = ServiceSchemaFactory::createAttribute($attributeId, $attributeName, $attributeType, $valueType);
if (!$attribute->checkAttributeValueType($valueType)) {
throw new \Exception("Attribute属性valueType不正确! 节点路径 [" . $attributeElm->getNodePath() . "].attributeId=" . $attributeId);
}
if ("single" === $attributeType) {
ServiceSchemaReader::elementToSingleAttribute($attributeElm, $attribute);
} elseif ("multi" === $attributeType) {
ServiceSchemaReader::elementToMultiAttribute($attributeElm, $attribute);
} elseif ("complex" === $attributeType) {
ServiceSchemaReader::elementToComplexAttribute($attributeElm, $attribute);
} elseif ("multiComplex" === $attributeType) {
ServiceSchemaReader::elementToMultiComplexAttribute($attributeElm, $attribute);
} else {
throw new \Exception("Attribute属性type类型不正确! 节点路径 [" . $attributeElm->getNodePath() . "].attributeId=" . $attributeId);
}
return $attribute;
}
/**
* @throws Exception
*/
private static function elementToSingleAttribute($attributeElm, $attribute)
{
self::elementToRule($attributeElm, $attribute);
self::elementToOption($attributeElm, $attribute);
foreach ($attributeElm->getElementsByTagName('value') as $value) {
if ($value->parentNode === $attributeElm) {
$attribute->setValues($value->nodeValue);
//只取第一个<value>标签
break;
}
}
}
/**
* @throws Exception
*/
private static function elementToMultiAttribute($attributeElm, $attribute)
{
self::elementToRule($attributeElm, $attribute);
self::elementToOption($attributeElm, $attribute);
foreach ($attributeElm->getElementsByTagName('values') as $values) {
if ($values->parentNode === $attributeElm) {
$valueArr = array();
foreach ($values->getElementsByTagName('value') as $value) {
if ($value->parentNode === $values) {
$valueArr[] = $value->nodeValue;
}
}
$attribute->setValues($valueArr);
//只取第一个<values>标签
break;
}
}
}
/**
* @throws Exception
*/
private static function elementToComplexAttribute($attributeElm, $attribute)
{
self::elementToRule($attributeElm, $attribute);
foreach ($attributeElm->getElementsByTagName('attributes') as $attributes) {
if ($attributes->parentNode === $attributeElm) {
$attributeArr = array();
foreach ($attributes->getElementsByTagName('attribute') as $item) {
if ($item->parentNode === $attributes) {
$attributeType = $item->getAttribute("type");
if ("single" === $attributeType || "multi" === $attributeType) {
$attributeArr[] = self::elementToAttribute($item);
}
} else {
throw new \Exception("Attribute属性type类型不正确! 节点路径 [" . $item->getNodePath() . "]");
}
}
$attribute->setValues($attributeArr);
//只取第一个<attributes>标签
break;
}
}
}
/**
* @throws Exception
*/
private static function elementToMultiComplexAttribute($attributeElm, $attribute)
{
$attributeArr = array();
foreach ($attributeElm->getElementsByTagName('attributes') as $attributes) {
if ($attributes->parentNode === $attributeElm) {
$complexAttr = new XMLAttribute();//每一个$complexAttr都是一个ComplexAttribute对象
$valuesArr = array();
foreach ($attributes->getElementsByTagName('attribute') as $item) {
if ($item->parentNode === $attributes) {
$attributeType = $item->getAttribute("type");
if ("single" === $attributeType || "multi" === $attributeType) {
$valuesArr[] = self::elementToAttribute($item);
}
} else {
throw new \Exception("Attribute属性type类型不正确! 节点路径 [" . $item->getNodePath() . "]");
}
}
$complexAttr->setValues($valuesArr);
$attributeArr[] = $complexAttr;
}
}
$attribute->setValues($attributeArr);
}
/**
* @throws Exception
*/
private static function elementToRule($attributeElm, $attribute)
{
foreach ($attributeElm->getElementsByTagName('rules') as $rules) {
if ($rules->parentNode === $attributeElm) {
$ruleArr = array();
foreach ($rules->getElementsByTagName('rule') as $rule) {
if ($rule->parentNode === $rules) {
$ruleType = $rule->getAttribute("type");
$ruleName = $rule->getAttribute("name");
$ruleValue = $rule->getAttribute("value");
if (self::checkEmpty($ruleValue)) {
throw new \Exception("id=[" . $attribute->getId() . "] AttrRule格式错误!AttrRule缺少value!");
}
$ruleObj = ServiceSchemaFactory::createRule($ruleType, $ruleName, $ruleValue);
if (!$ruleObj->checkRuleType($ruleType)) {
throw new \Exception("id=[" . $attribute->getId() . "] AttrRule类型type不合法!");
}
$ruleArr[] = $ruleObj;
}
}
$attribute->setRules($ruleArr);
//只取第一个<rules>标签
break;
}
}
}
/**
* @throws Exception
*/
private static function elementToOption($attributeElm, $attribute)
{
foreach ($attributeElm->getElementsByTagName('options') as $options) {
if ($options->parentNode === $attributeElm) {
$optionsArr = array();
foreach ($options->getElementsByTagName('option') as $option) {
if ($option->parentNode === $options) {
$displayName = $option->getAttribute("displayName");
if (self::checkEmpty($displayName)) {
throw new \Exception("id=[" . $attribute->getId() . "] Option格式错误!Option名称displayName不能为空!");
}
$value = $option->getAttribute("value");
if (self::checkEmpty($value)) {
throw new \Exception("id=[" . $attribute->getId() . "] Option格式错误!Option的值value不能为空!");
}
$optionObj = ServiceSchemaFactory::createOption($displayName, $value);
$optionsArr[] = $optionObj;
}
}
$attribute->setOptions($optionsArr);
//只取第一个<options>标签
break;
}
}
}
private static function checkEmpty($value)
{
if (is_null($value))
return true;
if (trim($value) == "")
return true;
return false;
}
/**
* @throws Exception
*/
static function errorHandler($errno, $errstr, $errfile, $errline)
{
throw new \Exception($errstr);
return true;
}
}

View File

@@ -0,0 +1,36 @@
<?php
class ServiceSchemaWriter
{
/**
* @throws Exception
*/
public static function writeSchemaXmlString(array $attributesArr)
{
$dom = new DOMDocument('1.0', 'utf-8');
$root = $dom->createElement("serviceSchema");
foreach ($attributesArr as $attribute) {
if ($attribute instanceof XMLAttribute) {
$attribute->toValueElement($dom, $root);
}
}
$dom->appendChild($root);
return $dom->saveXML($dom->documentElement);
}
/**
* @throws Exception
*/
public static function writeFullchemaXmlString(array $attributesArr)
{
$dom = new DOMDocument('1.0', 'utf-8');
$root = $dom->createElement("serviceSchema");
foreach ($attributesArr as $attribute) {
if ($attribute instanceof XMLAttribute) {
$attribute->toElement($dom, $root);
}
}
$dom->appendChild($root);
return $dom->saveXML($dom->documentElement);
}
}

View File

@@ -0,0 +1,342 @@
<?php
class XMLAttribute
{
private $id;
private $name;
private $type;
private $valueType;
private $rules;
private $options;
private $values;
public function checkAttributeValueType($attributeValueType)
{
$valueTypeArr = array(
"text" => "文本类型",
"boolean" => "boolean类型",
"numeric" => "数据类型",
"enum" => "枚举型",
"object" => "对象型"
);
if (empty($attributeValueType)) return false;
// foreach ($valueTypeArr as $key => $value){
// if($attributeValueType === $key) return true;
// }
if (array_key_exists($attributeValueType, $valueTypeArr)) return true;
return false;
}
/**
* @throws Exception
*/
public function toElement($dom, $parent)
{
$this->checkAttribute();
if ("single" === $this->type || "multi" === $this->type) {
$attributeElm = $this->appendAttributeValues($dom, $parent, $this);
$this->appendRulesElement($dom, $attributeElm, $this->rules, $this->id);
$this->appendOptionsElement($dom, $attributeElm, $this->options, $this->id);
} elseif ("complex" === $this->type) {
$attributeElm = $dom->createElement("attribute");
$attributeElm->setAttribute("id", $this->id);
$attributeElm->setAttribute("type", $this->type);
if ($this->name != "" && !is_null($this->name)) {
$attributeElm->setAttribute("name", $this->name);
}
if ($this->checkAttributeValueType($this->valueType)) {
$attributeElm->setAttribute("valueType", $this->valueType);
}
$attributesElm = $dom->createElement("attributes");
if (is_array($this->values)) {
foreach ($this->values as $attribute) {
if ($attribute instanceof XMLAttribute) {
$attributeElmTmp = $this->appendAttributeValues($dom, $attributesElm, $attribute);
$this->appendRulesElement($dom, $attributeElmTmp, $attribute->rules, $attribute->id);
$this->appendOptionsElement($dom, $attributeElmTmp, $attribute->options, $attribute->id);
}
}
} elseif (!empty($this->values)) {//complex类型的values必须是数组 或 空
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($attributesElm);
$this->appendRulesElement($dom, $attributeElm, $this->rules, $this->id);
$parent->appendChild($attributeElm);
} elseif ("multiComplex" === $this->type) {
$attributeElm = $dom->createElement("attribute");
$attributeElm->setAttribute("id", $this->id);
if ($this->name != "" && !is_null($this->name)) {
$attributeElm->setAttribute("name", $this->name);
}
$attributeElm->setAttribute("type", $this->type);
$attributeElm->setAttribute("valueType", "object");
if (is_array($this->values)) {
foreach ($this->values as $complexAttribute) {
if ($complexAttribute instanceof XMLAttribute) {
$attributesElm = $dom->createElement("attributes");
if (is_array($complexAttribute->getValues())) {
foreach ($complexAttribute->getValues() as $attribute) {
if ($attribute instanceof XMLAttribute) {
if (!$this->checkAttributeValueType($attribute->getValueType())) {
throw new \Exception("id=[" . $attribute->getId() . "] XMLAttribute属性valueType不正确!");
}
$attributeElmTmp = $this->appendAttributeValues($dom, $attributesElm, $attribute);
$this->appendRulesElement($dom, $attributeElmTmp, $attribute->rules, $attribute->id);
$this->appendOptionsElement($dom, $attributeElmTmp, $attribute->options, $attribute->id);
}
}
} elseif (!empty($complexAttribute->getValues())) {//complex类型的values必须是数组 或 空
throw new \Exception("id=[" . $complexAttribute->getId() . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($attributesElm);
}
}
} elseif (!empty($this->values)) {//multiComplex类型的values必须是数组 或 空
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性values不合法!");
}
$parent->appendChild($attributeElm);
} else {
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性type类型不正确!");
}
}
/**
* @throws Exception
*/
public function toValueElement($dom, $parent)
{
$this->checkAttribute();
if ("single" === $this->type || "multi" === $this->type) {
$this->appendAttributeValues($dom, $parent, $this);
} elseif ("complex" === $this->type) {
$attributeElm = $dom->createElement("attribute");
$attributeElm->setAttribute("id", $this->id);
$attributeElm->setAttribute("type", $this->type);
if ($this->name != "" && !is_null($this->name)) {
$attributeElm->setAttribute("name", $this->name);
}
if ($this->checkAttributeValueType($this->valueType)) {
$attributeElm->setAttribute("valueType", $this->valueType);
}
$attributesElm = $dom->createElement("attributes");
if (is_array($this->values)) {
foreach ($this->values as $attribute) {
if ($attribute instanceof XMLAttribute) {
$this->appendAttributeValues($dom, $attributesElm, $attribute);
}
}
} elseif (!empty($this->values)) {//complex类型的values必须是数组 或 空
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($attributesElm);
$parent->appendChild($attributeElm);
} elseif ("multiComplex" === $this->type) {
$attributeElm = $dom->createElement("attribute");
$attributeElm->setAttribute("id", $this->id);
if ($this->name != "" && !is_null($this->name)) {
$attributeElm->setAttribute("name", $this->name);
}
$attributeElm->setAttribute("type", $this->type);
$attributeElm->setAttribute("valueType", "object");
if (is_array($this->values)) {
foreach ($this->values as $complexAttribute) {
if ($complexAttribute instanceof XMLAttribute) {
$attributesElm = $dom->createElement("attributes");
if (is_array($complexAttribute->getValues())) {
foreach ($complexAttribute->getValues() as $attribute) {
if ($attribute instanceof XMLAttribute) {
if (!$this->checkAttributeValueType($attribute->getValueType())) {
throw new \Exception("id=[" . $attribute->getId() . "] XMLAttribute属性valueType不正确!");
}
$this->appendAttributeValues($dom, $attributesElm, $attribute);
}
}
} elseif (!empty($complexAttribute->getValues())) {//complex类型的values必须是数组 或 空
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($attributesElm);
}
}
} elseif (!empty($this->values)) {//multiComplex类型的values必须是数组 或 空
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性values不合法!");
}
$parent->appendChild($attributeElm);
} else {
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性type类型不正确!");
}
}
/**
* @throws Exception
*/
protected function appendAttributeValues($dom, $parent, $attribute)
{
$attributeElm = $dom->createElement("attribute");
if ($attribute->getId() != "" && !is_null($attribute->getId())) {
$attributeElm->setAttribute("id", $attribute->getId());
}
if ($attribute->getName() != "" && !is_null($attribute->getName())) {
$attributeElm->setAttribute("name", $attribute->getName());
}
if ($attribute->getType() != "" && !is_null($attribute->getType())) {
$attributeElm->setAttribute("type", $attribute->getType());
}
if ($this->checkAttributeValueType($attribute->getValueType())) {
$attributeElm->setAttribute("valueType", $attribute->getValueType());
}
$values = $attribute->getValues();
if ("single" === $attribute->getType()) {
$valueElm = $dom->createElement("value");
if (is_string($values)) {
$text = $dom->createTextNode($values);
$valueElm->appendChild($text);
} elseif (!is_null($values)) {//single类型的values必须是字符串 或 空
throw new \Exception("id=[" . $attribute->getId() . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($valueElm);
$parent->appendChild($attributeElm);
} elseif ("multi" === $attribute->getType()) {
$valuesElm = $dom->createElement("values");
if (is_array($values)) {
foreach ($values as $value) {
if (is_string($value) || is_null($value)) {
$valueElm = $dom->createElement("value", $value);
$valuesElm->appendChild($valueElm);
}
}
} elseif (!empty($values)) {//multi类型的values必须是数组 或 空
throw new \Exception("id=[" . $attribute->getId() . "] XMLAttribute属性values不合法!");
}
$attributeElm->appendChild($valuesElm);
$parent->appendChild($attributeElm);
} else {
throw new \Exception("id=[" . $attribute->getId() . "] XMLAttribute属性type类型不正确!");
}
return $attributeElm;
}
/**
* @throws Exception
*/
protected function appendRulesElement($dom, $parent, $rules, $attributeId)
{
if (empty($rules)) return;
if (!is_array($rules)) {
throw new \Exception("id=[" . $attributeId . "] XMLAttribute属性rules不合法!");
}
$rulesElm = $dom->createElement("rules");
foreach ($rules as $rule) {
if ($rule instanceof AttributeRule) {
$rule->toElement($dom, $rulesElm, $attributeId);
}
}
$parent->appendChild($rulesElm);
}
/**
* @throws Exception
*/
protected function appendOptionsElement($dom, $parent, $options, $attributeId)
{
if (empty($options)) return;
if (!is_array($options)) {
throw new \Exception("id=[" . $attributeId . "] XMLAttribute属性options不合法!");
}
$optionsElm = $dom->createElement("options");
foreach ($options as $option) {
if ($option instanceof Option) {
$option->toElement($dom, $optionsElm, $attributeId);
}
}
$parent->appendChild($optionsElm);
}
/**
* @throws Exception
*/
protected function checkAttribute()
{
if (empty($this->id) && $this->id != '0') {
throw new \Exception("XMLAttribute属性缺少id!");
}
if (empty($this->type) && $this->type != '0') {
throw new \Exception("id=[" . $this->id . "] XMLAttribute属性缺少type");
}
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
public function getValueType()
{
return $this->valueType;
}
public function setValueType($valueType)
{
$this->valueType = $valueType;
}
public function getRules()
{
return $this->rules;
}
public function setRules($rules)
{
$this->rules = $rules;
}
public function getOptions()
{
return $this->options;
}
public function setOptions($options)
{
$this->options = $options;
}
public function getValues()
{
return $this->values;
}
public function setValues($values)
{
$this->values = $values;
}
}