Commit 15534ea4 authored by luhongguang's avatar luhongguang
parents ac7e4d03 2150d5e7
...@@ -179,6 +179,56 @@ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUbC5cW6K/XPjfdljTRSP5YtZG ...@@ -179,6 +179,56 @@ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUbC5cW6K/XPjfdljTRSP5YtZG
gHM3r3EWS2bUGHTZZLAd6KGrIP2985c9ODd3s3/JvYmrh/N3djFy3MYhZm5P6iGt gHM3r3EWS2bUGHTZZLAd6KGrIP2985c9ODd3s3/JvYmrh/N3djFy3MYhZm5P6iGt
kRlCF7Jac58/9V4lDhQiMzjclfpWR6s3aMBEwx5g2gFhjnnlSZRnYofRPqsB1JhB kRlCF7Jac58/9V4lDhQiMzjclfpWR6s3aMBEwx5g2gFhjnnlSZRnYofRPqsB1JhB
1ZirI2if7kWNBz+BTwIDAQAB 1ZirI2if7kWNBz+BTwIDAQAB
-----END PUBLIC KEY-----';
/**
* 商户系统拼单小程序 SERVER端私钥与客户端公钥
*/
const MERCHANT_PUB_PIN_PRIVATE_KEY_STR = '-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMq5OJZpmPbfrGAt
JIvPQEEYr0edc4U7LmUArp17tUeknqNfFc0pXuWABIkMTeZuKspDf1ehfYPCVnGs
gWIYvECAdAvMH8TpgNMl6Bc7hjRY89gZUuIx5SK0kw8xJ1z2SlQ4at2PiUnNjYYC
ydyipoHOAXYgpEbcX4OGEF6P6E/nAgMBAAECgYBQsOULScDvExzjs1RGqhnjT1YF
ZXCj6WiQH3Nhj+oaODZExQZCgWMaaphjjJg9TkCN/cvkL41sMqCB4q4lQ786H/8P
flBDGyngi9vjmZBdsmllDNi7kwcAtl8xk7YaHzQuIZ49dOzL/qQggCHokgvbBRXh
NI1AYBm/G8C8H0DE8QJBAOlKL4LQuoOtg49+qpw73snNOkEnFzn6nClud7w/wHR1
I82nmesyadcjVoJA9Lb1/AA9/MXV5RQeZ8Ckn//42SUCQQDedUsl4jtpuLz+QYv4
994ASsGBSGLE3BAPI1YClA8oVDRYMQydbZMgeZ8AspZtnmBifbcoOM/q+VbBomNk
pfUbAkEAkUCMhnG5v6T4hg7C4ZXxaEqs28YgEwxz0OQkDwTOqnQI/9I75pI0DizF
f0I8W/Kanff6e59rC3TG+s5FhNYHNQJBAJtOlCpcqVID8Z4osMoeclUN286gdKQv
Zt7Ksq+WIobrUqgHhmEaMM9JWaKpC7B4E55vWkGweCf574G8F1wbKOUCQHtD5JLr
B/84pKhIkdbhfdTReLbxz3/mRZM+RGFvbXvr5yr5ihcFHtIgHsmrIYbBccJdd42s
kZ5U8STIJSCkBZo=
-----END PRIVATE KEY-----';
const MERCHANT_PUB_PIN_PUBLIC_KEY_STR = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGmANRSw3T4ztQ8ZWMw+cW70Zg
9yOwQV0oWp9Zce8eCLoRgFVFeajeQ1BT59tQ3bR4Qwg/gL8ZKf9JanxNyINQY8th
CKIYerOCxgr0QPKiQCVL7BTZNj7m91OdVmsYfJty1YihM43a5op62T0OJk/4mF2H
Txl13uSJhZgM9szI7wIDAQAB
-----END PUBLIC KEY-----';
/**
* 商户系统拼单小程序-测试 SERVER端私钥与客户端公钥
*/
const TEST_MERCHANT_PUB_PIN_PRIVATE_KEY_STR = '-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOOfrgheB6r+85+1
97tfjq6+R/FhWg4T+GXOZ5pimMNwf/yOLYbC+HITvHKoEExymf2Um6i6dnJjU7zl
AjmbzK0TSab0exz1tNxnBSE/nt5G06n5f2FOYMAu67iseQ97aGYDGbRWakSjdYTx
jPoKT7dG8cC6RdIW7aJDCceNIeGBAgMBAAECgYByZakIaYF/Dd0Q0lor4E2MQvNT
O7MPyjeXqtFkxNKzvpGEM0xsIwbMBmE6Wn6+fQYpbIuClBu9R3ApSgsBOuz0yBGM
e/DNmAifZn1EFVQRm+Li//poLfl3HE2oj0dJhPRiCyoxeWhP76zxP+v0IXwopZbF
W0jP+ojto8q2zx/75QJBAPxFSQisRdMV1KxbyZzT2clYwRB5Dfqdh2SmaJ6Mms+o
Ua9e6lgD7/K1C+3GCtIkDHSlhnNNMRwIItpCe8r7RZcCQQDm/R5it0UvpWZzYCEn
iXMvavwp3+PCTftpxS9/CWrWQCk5C4wW7l5j+Be6f0e4cboOr6kaiPXkF8qn/SF6
S+SnAkBNs6GNNFLFc6Hv/M2aqn4YUGgXBNJTcRX04HS08SX19ChE1f1kYsIThcRI
1okatNPJUfqZpRsNQUxK4dNzb/W9AkBJ+S3N91tU0udoc5SqkL4upVh0IJtUEp09
VkTLrjxkuM960VPf1B6ubTlMJI7XZrRrF55UPSBiF6xy+AHMpJlpAkEAhNVjlx+x
9qDJ23tHTDFxN0dl2IK+Xz3j9HDNvb5SdO+pcIvQvVg9UUc5xnkXmVm35RwqeA6O
2P6ROLCijjotzw==
-----END PRIVATE KEY-----';
const TEST_MERCHANT_PUB_PIN_PUBLIC_KEY_STR = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFOU3D4aULZuJ3IyRGmPhwn5g
zIcDvT2EEZMJ+ePgi0Oax/P3z25m5758okGs1lrS93vDWO7lbsgQn5mnuKuqmuj6
M3BP/vOildi+3oTZcjQTV2deebIrhW4p96DvTqQ7ixVAEi4of3XoITA00J8hfNy9
jDprGYGJ5yeTuRRHlQIDAQAB
-----END PUBLIC KEY-----'; -----END PUBLIC KEY-----';
/** /**
* TEST SERVER端私钥与客户端公钥 * TEST SERVER端私钥与客户端公钥
...@@ -235,6 +285,14 @@ mnRjVUtXBgEF0A9xt2QVNMQovtjJ2rkg43gVByDKbOsUqbJYjA12IpALMdECHCMl ...@@ -235,6 +285,14 @@ mnRjVUtXBgEF0A9xt2QVNMQovtjJ2rkg43gVByDKbOsUqbJYjA12IpALMdECHCMl
'pub_key' => self::TEST_MERCHANT_H5_PUBLIC_KEY_STR, 'pub_key' => self::TEST_MERCHANT_H5_PUBLIC_KEY_STR,
'pri_key' => self::TEST_MERCHANT_H5_PRIVATE_KEY_STR, 'pri_key' => self::TEST_MERCHANT_H5_PRIVATE_KEY_STR,
], ],
'merchant-pub-pin' => [
'pub_key' => self::MERCHANT_PUB_PIN_PUBLIC_KEY_STR,
'pri_key' => self::MERCHANT_PUB_PIN_PRIVATE_KEY_STR,
],
'test-merchant-pub-pin' => [
'pub_key' => self::TEST_MERCHANT_PUB_PIN_PUBLIC_KEY_STR,
'pri_key' => self::TEST_MERCHANT_PUB_PIN_PRIVATE_KEY_STR,
],
'test' => [ 'test' => [
'pub_key' => self::TEST_PUBLIC_KEY_STR, 'pub_key' => self::TEST_PUBLIC_KEY_STR,
'pri_key' => self::TEST_PRIVATE_KEY_STR, 'pri_key' => self::TEST_PRIVATE_KEY_STR,
......
...@@ -196,6 +196,11 @@ class HttpUtil ...@@ -196,6 +196,11 @@ class HttpUtil
{ {
$ch = curl_init($url); $ch = curl_init($url);
// CURLOPT_POSTFIELDS 不支持多维数组
if (is_array($post) && count($post) != count($post, COUNT_RECURSIVE)) {
$post = http_build_query($post);
}
if (is_resource($ch) === true) if (is_resource($ch) === true)
{ {
curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_setopt($ch, CURLOPT_FAILONERROR, true);
...@@ -365,7 +370,7 @@ class HttpUtil ...@@ -365,7 +370,7 @@ class HttpUtil
{ {
//过滤无意义的日志 //过滤无意义的日志
$log = true; $log = true;
$excludes = config('http_util', 'log.exclude'); $excludes = config('request', 'log.exclude');
if (!empty($excludes)) { if (!empty($excludes)) {
foreach ($excludes as $exclude) { foreach ($excludes as $exclude) {
if (is_array($urls)) { if (is_array($urls)) {
......
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
namespace Api\PhpUtils\Log; namespace Api\PhpUtils\Log;
use Api\PhpUtils\Cache\ApcuUtil;
use Api\PhpUtils\Log\Tracer;
use Api\PhpUtils\Message\Email; use Api\PhpUtils\Message\Email;
class FileLog class FileLog
{ {
const PREFIX_FILELOG_ERROR = 'flerr:';
/** /**
* 用于记录info级别的错误 * 用于记录info级别的错误
* 会记录请求上下文,不会发生报警邮件 * 会记录请求上下文,不会发生报警邮件
...@@ -15,7 +18,8 @@ class FileLog ...@@ -15,7 +18,8 @@ class FileLog
*/ */
public static function info($signature, $detail_info = '', $with_access_log = false) public static function info($signature, $detail_info = '', $with_access_log = false)
{ {
$log = 'PHP User_info: [' . $signature . ']' . ' [detail info:] ' . $detail_info; $traceId = Tracer::getTraceId();
$log = 'PHP User_info: [' . $signature . '] [traceId:'. $traceId .'] [detail info:] ' . $detail_info;
if ($with_access_log) { if ($with_access_log) {
$log .= ' [request info:] ' . self::accessLog(); $log .= ' [request info:] ' . self::accessLog();
} }
...@@ -31,7 +35,8 @@ class FileLog ...@@ -31,7 +35,8 @@ class FileLog
*/ */
public static function waring($signature, $detail_info = '', $exception = null) public static function waring($signature, $detail_info = '', $exception = null)
{ {
$log = 'PHP User_warning: [' . $signature . ']' . ' [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog(); $traceId = Tracer::getTraceId();
$log = 'PHP User_warning: [' . $signature . '] [traceId:'. $traceId .'] [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog();
if ($exception != '') { if ($exception != '') {
$exception_info = 'In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage(); $exception_info = 'In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage();
$log .= ' [exception info: ]' . $exception_info; $log .= ' [exception info: ]' . $exception_info;
...@@ -49,34 +54,36 @@ class FileLog ...@@ -49,34 +54,36 @@ class FileLog
*/ */
public static function error($signature, $detail_info = '', $exception = null, $mail_to = '') public static function error($signature, $detail_info = '', $exception = null, $mail_to = '')
{ {
$log = 'PHP User_error: [' . $signature . ']' . ' [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog(); $traceId = Tracer::getTraceId();
$log = 'PHP User_error: [' . $signature . '] [traceId:'. $traceId .'] [detail info:] ' . $detail_info . ' [request info:] ' . self::accessLog();
if ($exception != '') { if ($exception != '') {
$exception_info = ' [exception info: ] In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage(); $exception_info = ' [exception info: ] In ' . $exception->getFile() . ' on line ' . $exception->getLine() . ' ' . $exception->getCode() . ': ' . $exception->getMessage();
} else { } else {
$exception_info = ''; $exception_info = '';
} }
$log .= ' [exception info: ]' . $exception_info; $log .= ' [exception info: ]' . $exception_info;
$log .= ' [debug_backtrace info: ]' . print_r(debug_backtrace(), 1);
error_log($log); error_log($log);
if (!empty($mail_to)) { if (empty($mail_to)) {
$subject = 'App api #' . $signature . '# ' . $_SERVER['SERVER_NAME'] . ' (' . $_SERVER['SERVER_ADDR'] . ') Alert Message'; $mail_to = 'bp-server@yidian-inc.com';
$body = 'Error: ' . $signature . "\n\n"; }
$body .= 'Detail info: ' . $detail_info . "\n\n"; $subject = 'App api #' . $signature . '# ' . $_SERVER['SERVER_NAME'] . ' (' . $_SERVER['SERVER_ADDR'] . ') Alert Message';
$body .= 'Exception info: ' . $exception_info . "\n\n"; $body = 'Error: ' . $signature . "\n\n";
$body .= 'Request info: ' . self::accessLog() . "\n\n"; $body .= 'Detail info: ' . $detail_info . "\n\n";
$body .= 'Machine: ' . gethostname(); $body .= 'Exception info: ' . $exception_info . "\n\n";
if (!is_array($mail_to)) { $body .= 'Request info: ' . self::accessLog() . "\n\n";
$mail_to = [$mail_to]; $body .= 'Machine: ' . gethostname();
} if (!is_array($mail_to)) {
$mail_to = [$mail_to];
}
if (self::shouldSendEmail(md5($signature)) === true) {
foreach ($mail_to as $mail) { foreach ($mail_to as $mail) {
$key = md5(sprintf("%s,%s", $mail, md5($signature))); Email::sendMail('bp-noreply@yidian-inc.com', $mail, $subject, $body);
if (self::shouldSendEmail($key) === true) {
Email::sendMail('bp-noreply@yidian-inc.com', $mail, $subject, $body);
}
} }
} }
} }
private static function accessLog() public static function accessLog()
{ {
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME']; $url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME'];
$query = http_build_query($_GET, '', '&'); $query = http_build_query($_GET, '', '&');
...@@ -102,7 +109,7 @@ class FileLog ...@@ -102,7 +109,7 @@ class FileLog
fclose($log_file); fclose($log_file);
} }
private static function ip() public static function ip()
{ {
if (isset($_SERVER['IPV6_REMOTE_ADDR']) && !empty($_SERVER['IPV6_REMOTE_ADDR']) && trim($_SERVER['IPV6_REMOTE_ADDR']) !== '-') { // 如果没有ipv6地址, 运维会传一个占位符“-” if (isset($_SERVER['IPV6_REMOTE_ADDR']) && !empty($_SERVER['IPV6_REMOTE_ADDR']) && trim($_SERVER['IPV6_REMOTE_ADDR']) !== '-') { // 如果没有ipv6地址, 运维会传一个占位符“-”
$ips = $_SERVER['IPV6_REMOTE_ADDR']; $ips = $_SERVER['IPV6_REMOTE_ADDR'];
...@@ -119,13 +126,14 @@ class FileLog ...@@ -119,13 +126,14 @@ class FileLog
return $ip[0]; return $ip[0];
} }
private static function shouldSendEmail($key) public static function shouldSendEmail($key)
{ {
$result = true; $result = true;
// $cache = new CommonCacheUtil(RedisUtil::CODIS_CLUSTER_ACTION); // 每分钟发一条
// if ($cache->add($key, true, 60, CacheUtil::PREFIX_SEND_MAIL) === false) { if (! ApcuUtil::apcu_add_one(self::PREFIX_FILELOG_ERROR, $key, 1, 60)) {
// $result = false; $result = false;
// } }
return $result; return $result;
} }
} }
<?php
namespace Api\PhpUtils\Log;
class Tracer {
const DEBUG = 1;
const INFO = 2;
const WARNING = 3;
const ERROR = 4;
protected static $traceId = '';
protected static $spanId = '';
/**
* http 请求日志
*/
public static function request() {
$tag = 'request';
$message = 'request log';
$content = [
'uri'=>'',
'get'=>[],
'post'=>[],
];
//__METHOD__
self::info($message, $content, $tag);
}
/**
* @param $ret
*/
public static function response($ret) {
$tag = 'response';
$message = 'response log';
$content = [
'ret'=>$ret,
'requestId'=>self::getTraceId(),
];
self::info($message, $content, $tag);
}
public static function daemon() {
$tag = 'daemon';
$message = 'daemon log';
$content = [
'pid'=>posix_getpid(),
];
self::info($message, $content, $tag);
}
/**
* @param $message
* @param array $content
* @param string $tag
*/
public static function debug($message, $content = [], $tag = ''){
self::log(self::DEBUG, $message, $content, $tag);
}
public static function info($message, $content = [], $tag = ''){
self::log(self::INFO, $message, $content, $tag);
}
public static function warning($message, $content = [], $tag = '') {
self::log(self::WARNING, $message, $content, $tag);
}
public static function error($message, $content = [], $tag = '') {
self::log(self::ERROR, $message, $content, $tag);
}
public static function log($level, $message, $content, $tag) {
if (!defined('LOG_PATH')) {
define('LOG_PATH', ROOT_PATH.'/logs/');
}
switch ($level) {
case self::DEBUG:
case self::INFO:
case self::WARNING:
case self::ERROR:
$file = LOG_PATH . 'log_' . date('Y-m-d') . '.log';
break;
}
$dateTime = new \DateTime();
$log = [
'timestamp'=>$dateTime->format(\DateTime::RFC3339_EXTENDED),
'traceId'=>self::getTraceId(),
'spanId'=>self::getSpanId(),
'tag'=>$tag,
'content'=>$content,
'message'=>$message
];
//$_SERVER['HTTP_X_FORWARDED_FOR']
$string = json_encode($log, JSON_UNESCAPED_UNICODE) . "\n";
if($fd = @fopen($file, 'a')) {
fputs($fd, $string);
fclose($fd);
}
}
/**
* @return false|mixed|string
* 获取traceId
*/
public static function getTraceId() {
if(empty(self::$traceId)) {
if(!empty($_SERVER['HTTP_X_TRACE_ID'])) {
self::$traceId = $_SERVER['HTTP_X_TRACE_ID'];
} elseif(!empty($_SERVER['HTTP_X_REQUEST_ID'])) {
self::$traceId = $_SERVER['HTTP_X_REQUEST_ID'];
} else {
self::$traceId = self::genUniqId();
}
}
return self::$traceId;
}
/**
* @return false|string
* 获取spanId
*/
public static function getSpanId() {
if(empty(self::$spanId)) {
self::$spanId = self::genUniqId();
}
return self::$spanId;
}
/**
* @return false|string
* @throws \Exception
* 获取随机串用于记录traceId
*/
public static function genUniqId() {
if (function_exists("random_bytes")) {
$bytes = random_bytes(ceil(8));
return substr(bin2hex($bytes), 0, 16);
} elseif (function_exists("openssl_random_pseudo_bytes")) {
$bytes = openssl_random_pseudo_bytes(ceil(8));
return substr(bin2hex($bytes), 0, 16);
} else {
$pre = rand(1, 4095);
return uniqid(sprintf("%03x", $pre));
}
}
}
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Api\PhpUtils\Message; namespace Api\PhpUtils\Message;
use Yaf\Application;
class Email class Email
{ {
/** /**
...@@ -19,6 +21,10 @@ class Email ...@@ -19,6 +21,10 @@ class Email
if (empty($to)) { if (empty($to)) {
return false; return false;
} }
$env = Application::app()->environ();
if($env != 'test' && $env != 'prod' && $env != 'perf'){
return false;
}
if (empty($from)) { if (empty($from)) {
$from = 'noreply@yidian-inc.com'; $from = 'noreply@yidian-inc.com';
} }
...@@ -30,6 +36,16 @@ class Email ...@@ -30,6 +36,16 @@ class Email
fwrite($sock, "HELO " . $domain . "\r\n"); fwrite($sock, "HELO " . $domain . "\r\n");
fgets($sock); fgets($sock);
fwrite($sock, "auth login\r\n");
fgets($sock);
fwrite($sock, "YnAtbm9yZXBseQ==\r\n");
fgets($sock);
fwrite($sock, "VlhObGNtNWhiJFclVTY=\r\n");
fgets($sock);
fwrite($sock, "MAIL FROM:<" . $from . ">\r\n"); fwrite($sock, "MAIL FROM:<" . $from . ">\r\n");
fgets($sock); fgets($sock);
if (!is_array($to)) { if (!is_array($to)) {
......
...@@ -70,7 +70,7 @@ class MonUtil{ ...@@ -70,7 +70,7 @@ class MonUtil{
} }
//接口返回状态码打点 //接口返回状态码打点
if(!empty($code) && is_numeric($code)){ if(isset($code) && is_numeric($code)){
$result = self::counting($module . "." . (string)$request_uri, (string)$code,1) . "\n"; $result = self::counting($module . "." . (string)$request_uri, (string)$code,1) . "\n";
}else{ }else{
$result = self::counting($module . "." . (string)$request_uri, (string)-999,1) . "\n"; $result = self::counting($module . "." . (string)$request_uri, (string)-999,1) . "\n";
......
...@@ -1077,7 +1077,7 @@ class Medoo ...@@ -1077,7 +1077,7 @@ class Medoo
$optimizer = ''; $optimizer = '';
if(is_null($options)) { if(is_null($options)) {
// 默认1秒钟超时时间 // 默认1秒钟超时时间
$optimizer = ' /*+ max_execution_time(1000)*/ '; $optimizer = ' /*+ max_execution_time(3000)*/ ';
}elseif(isset($options['max_execution_time'])) { }elseif(isset($options['max_execution_time'])) {
$ts = intval($options['max_execution_time']); $ts = intval($options['max_execution_time']);
$optimizer = ' /*+ max_execution_time('. $ts .')*/ '; $optimizer = ' /*+ max_execution_time('. $ts .')*/ ';
......
<?php
namespace Api\PhpUtils\Strategy;
/**
* Class ShareWorker
* @package Api\PhpUtils\Strategy
*
* 优惠券分摊处理算法
*/
class ShareWorker {
/**
* @param $items = ['sku_1'=>100, 'sku_2'=>85]
* @param $tip = 100
* @throws \ErrorException
* 根据商品价格等比做优惠金额的分摊, 做四舍五入。
*/
public static function coupon($items, $total_tip) {
if(!is_array($items) || $total_tip <= 0) {
throw new \ErrorException('输入分摊条件失败,请确认', '3001');
}
$total = 0;
foreach ($items as $k=>$price) {
if(!is_int($price) || $price < 0) {
throw new \ErrorException('存在金额非法,请核对金额', '3002');
}
$total += $price;
}
$ret = [];
$cleared = $cleared_tip = 0;
foreach ($items as $k=>$price) {
$left = $total - $cleared;
$ret[$k] = intval(round($price/$left * ($total_tip - $cleared_tip)));
$cleared_tip += $ret[$k];
$cleared += $price;
}
return $ret;
}
/**
* @param $mutiArr = [
['goods'=>['a1'=>600, 'a2'=>100, 'a3'=>1300], 'tip'=>100],
['goods'=>['a1'=>600, 'a2'=>600, 'a3'=>600], 'tip'=>4],
];
* @return array = [
['a1' => 30, 'a2' => 5, 'a3' => 65],
['a1' => 1, 'a2' => 2, 'a3' => 1]
];
* @throws \ErrorException
* 批量计算奖励,
*/
public static function batchCoupon($mutiArr) {
$ret = [];
foreach ($mutiArr as $k=>$item) {
$ret[$k] = self::coupon($item['goods'], $item['tip']);
}
return $ret;
}
}
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